David Steinsland – informatikkstudent og webutvikler

Innlegg fra kategorien «PHP»

Daglig backup av MySQL med PHP (Windows)

| Ingen kommentarer »

Dersom du drifter din egen server eller har en utviklingsserver på PC-en din, har du nok vært i situasjoner hvor du tenker: «Hvor er sikkerhetskopien når jeg trenger den?».

Jeg var der selv for omtrent en úke siden, hvor jeg ved en feiltakelse kjørte en gammel PHP-fil som overskrev hele Postnummer-databasen min. Heldigvis hadde jeg mange sikkerhetskopier av databasen, så det gikk bra.

Men hva om jeg ikke hadde hatt kopier? Da hadde faktisk hele arbeidet mitt vært ødelagt! Mangfoldige timer bortkastet, bokstavelig talt.

Hver dag (midnatt) blir livredderen utført: en planlagt oppgave i Windows kjører et PHP-skript som tar backup av MySQL.

I mine siste artikler har jeg skrevet litt om planlagte oppgaver i Windows, og vist flere ting du kan gjøre.

Teori

Når du installerte MySQL, fikk du med et program som heter mysqldump. Programmet brukes til å ta backup av MySQL; du kan selv spesifisere én eller flere databaser, eller om du ønsker å ta backup av alle.

Videre kommer jeg til å ta i bruk  PHP fra kommandolinjen, som muliggjør at vi kan bruke PHP-tolkeren til å kjøre en bestemt PHP-fil. Dette programmet ligger i installasjonsmappen til PHP, og heter php.exe

Jeg refererer til disse programmene som henholdsvis mysqldump og php fra kommandolinjen. Dette er fordi jeg har lagt til PHPs installasjonsmappe og bin-mappen til MySQL til miljøvariabelen PATH. Dette forteller Windows at når du skriver inn et program i CMD, skal den også leite etter det programmet i de plasseringene.

Dersom du ikke har gjort dette, må du spesifisere til programmene med full sti, eks: c:\php\php eller skrive inn følgende i CMD:

SET PATH = %PATH%;C:\PHP;C:\MySQL\bin

(jeg antar PHP og MySQL er installert i C:\).

Ved default ligger «.EXE» i miljøvariabelen PATHEXT, som medfører at du slipper å skrive «.exe» bak programnavnet.

PHP-filen

Gjør klar en PHP-fil som du navngir backup.php og plasser denne utenfor ServerRoot (altså en plass den ikke kan nåes via en nettleser).

ServerRoot hos meg er \www\public_html\, slik at jeg har plassert PHP-filen ett steg opp, i \www\ (Med baklengs-skråstrek foran stien, tolker Windows dette som C:\).

Lag så en mappe du kaller for backup i samme mappe hvor du har plassert PHP-filen. Dette er plassen hvor backupene våre kommer til å ligge.

Det første vi gjør i PHP-filen vår er å definere et par runtime-innstillinger, som databasetilkoblingen, plasseringen til backup-filene og hvordan filnavnet skal utformes.

// MySQL host
define ('HOST', 'localhost');
// MySQL username
define ('USER', 'username');
// MySQL password
define ('PW', 'password');

define ('DUMP_FILENAME', date ('Y-m-d-H-i') . '.sql'); // i.e. 2010-10-30-23-00.sql

define ('SELF_DIR', __DIR__ . DIRECTORY_SEPARATOR);
define ('BACKUP_DIR', 'backup' . DIRECTORY_SEPARATOR);

Backupfilene våre får navnet sitt basert på dagens dato og tidspunktet for når filen blir kjørt.

Neste steg er å kalle opp mysqldump:

passthru (sprintf ('mysqldump -h %s -u %s -p%s -A -r "%s"', HOST, USER, PW, SELF_DIR . BACKUP_DIR . DUMP_FILENAME));

Her trenger du ikke endre noe, bortsett fra stien til mysqldump om du ikke har endret PATH i Windows.

Argumentforklaring:

-h
Spesifiserer host-adressen til MySQL
-u
Brukernavnet til MySQL
-p
Passordet ditt MySQL-brukeren (-p og passordet skal ikke ha mellomrom mellom hverandre).
-A
Spesifiserer at vi skal ta backup av alle databasene. Alternativt –all-databases.
-r
Den fulle stien (plassering + filnavn) til hvor backupen ligger

Det neste jeg har valgt å gjøre, er å komprimere SQL-filen i et Zip-arkiv, som medfører at filstørrelsen blir endel mindre (noe som er bra!).

$Zip = new ZipArchive;
$Zip->open (SELF_DIR . BACKUP_DIR . DUMP_FILENAME . '.zip', ZipArchive::CREATE);
$Zip->setArchiveComment ('This database dump was automatically taken at ' . date ('H:i, d.m.Y') . ' by a Windows Scheduled Task');
$Zip->addFile (DUMP_FILENAME, SELF_DIR . BACKUP_DIR . DUMP_FILENAME);
unlink (SELF_DIR . BACKUP_DIR . DUMP_FILENAME);
$Zip->close();

Den planlagte oppgaven

Det siste steget vårt, er å opprette oppaven som skal kjøre PHP-skriptet. Jeg har valgt å kjøre denne oppgaven hver dag ved midnatt.

Opprett den planlagte oppgaven ved å skrive dette inn i CMD:

SCHTASKS /Create /SC DAILY /MO 1 /ST 00:00 /TN «MySQL Backup» /TR «php \www\backup.php»

Tips

Uten PHP

Dersom du ikke ønsker å komprimere filene med Zip, trenger du heller ikke anvende PHP til denne jobben. Da kjører du rett og slett bare mysqldump direkte i oppgaven:

SCHTASKS /Create /SC DAILY /MO 1 /ST 00:00 /TN «MySQL Backup» /TR «mysqldump -h <host> -u <brukernavn> -p<passord> -A -r \www\backups\database_dump.sql»

Husk at det ikke skal være mellomrom mellom -p og passordet!

Én eller flere databaser istedenfor alle

Erstatt -A i mysqldump-kommandoen med:

–database <database>

eller

–databases <database 1> <database 2> … <database n>

Garbage Collector

Det tar ikke lange tiden før backup-mappen blir full av filer; og strengt talt så trenger du ikke backups som ble tatt for måneder siden. Derfor kan det være lurt å sette opp en søppelsamler, som sletter gamle filer.
Da oppretter du en planlagt oppgave som kjører for eksempel \www\garbage.php hver uke. Innholdet i PHP-filen er å loope gjennom backup-mappen, og sjekke datoen på når filene sist ble modifisert (opprettet). Slik har jeg gjort det:

// How long we are keeping each file, since its creation date
// (in seconds)
define ('MAX_FILE_AGE', (60 * 60 * 24 * 7)); // 7 days

$data = glob (__DIR__ . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . '*.zip');

foreach ($data as $file)
{
	if (time() - filectime ($file) > MAX_FILE_AGE)
	{
		unlink ($file);
	}
}

Restarte Apache via PHP (Windows)

| Ingen kommentarer »

Det å jobbe med Apache og PHP på Windows kan ha sine konsekvenser, spesielt det at du ikke har tilgang til et eneste Linux-verktøy. Men det gjelder å tilpasse seg, noe jeg kan bevise i denne artikkelen.

Apache er installert med et program som heter httpd, hvor du for eksempel kan starte/stoppe serveren, sjekke hvilke moduler som er lastet inn og så videre. Jeg har tenkt å benytte meg av dette programmet, men trenger en fremgangsmåte.

Fremgangsmåter

Det er flere måter du kan restarte Apache på, men nå skal jeg prøve å beskrive mine to favoritter:

  1. Opprette en planlagt oppgave med PHP som kjøres én gang, og som restarter Apache
  2. Opprette en planlagt oppgave som kjører hvert minutt, og som sjekker om det finnes en bestemt fil på serveren. Om denne filen finnes, restarter vi Apache.

Med løsningen i første punkt er vi nødt til å kjøre PHP-filen for å restarte Apache, mens i den andre kan opprette denne spesielle filen via for eksempel FTP. Det hele er smak og behag, men jeg bruker løsningen i punkt 2 på min server, og det er denne jeg kommer til å skrive om videre.

Det første vi må gjøre er å opprette oppgaven som skal kjøres. Dette kan du gjøre enten via command prompt (CMD) eller via kontrollpanelet på Windows.

For å opprette oppgaven via CMD, skriver du inn følgende:

SCHTASKS /Create /TN «Apache Restarter» /SC MINUTE /MO 1 /TR C:\restart.vbs

Her oppretter vi en oppgave med navnet Apache Restarter som skal kjøre programmet C:\restart.vbs hvert minutt. Restart.vbs er programmet vårt som sjekker om den aktuelle filen eksisterer og som restarter Apache.

VBS er et nyttig skriptingspråk som brukes på Windows, og kan sammenlignes med Bash på Unix.

Opprett filen restart.vbs og lim inn følgende kode:

Set WshShell = CreateObject("WScript.Shell" )

REM # hiding the command prompt
If Instr(1, WScript.FullName, "CScript", vbTextCompare) = 0 Then
    WshShell.Run "cscript """ & WScript.ScriptFullName & """", 0, False
    WScript.Quit
End If

Set filesys = CreateObject("Scripting.FileSystemObject")
restart_flag = filesys.GetAbsolutePathName("C:\www\flags\restart")

If filesys.FileExists(restart_flag) Then
	filesys.DeleteFile (restart_flag), True
	WshShell.Exec ("httpd -k restart")
End If

Det eneste du trenger å endre her, er filnavnet «C:\www\flags\restart». På min server har jeg plassert denne i en mappe jeg har kalt for «flags». Filnavnet er «restart» uten noen filendelse.

Nå har vi egentlig satt opp rutinen vår:

Den planlagte oppgaven kjører restart.vbs hvert minutt, og det programmet sjekker om flagget «restart» finnes i mappen C:\www\flags\. Det eneste vi trenger å gjøre nå, er å opprette filen «restart» hver gang vi ønsker å restarte Apache: og det kan vi gjøre med PHP.

Opprett en ny fil som du kaller restart.php på serveren din, hvor du limer inn følgende kode:

$h = fopen ('C:\www\flags\restart', 'w+');
fclose ($h);

if (file_exists ('C:\www\flags\restart')) {
    echo 'Apache will restart within one minute.';
}

Hver gang du ønsker å restarte Apache kan du da kjøre den PHP-filen fra nettleseren din, eller opprette flagget «restart» via en FTP.

Jeg ønsker løsningen i punkt 1, hva gjør jeg?

Ideen er den samme, bare du oppretter en oppgave via PHP som skal kjøres én gang med parameteret «httpd -k restart»:

exec ('SCHTASKS /Create /TN "Apache Restart" /SC ONCE /TR "httpd -k restart" /st ' . date ('H:i', strtotime ('+1 minute'));

Her oppretter vi en oppgave som skal kjøres én gang ett minutt i fremtiden.

Last ned

Her følger en ZIP-fil med de kodene du trenger.
Last ned apache_restart.zip

NB: Jeg refererer til programmet httpd.exe som kun httpd. Dette er fordi jeg har lagt bin-mappen til Apache i miljøvariabelen PATH. Om du ikke har gjort dette, må du referere til programmet med full sti, eks: C:\Apache2.2\bin\httpd.exe

Dagens tips: Cronjobber på Windows med Wget

| Ingen kommentarer »

I mange ulike sammenhenger kan det være nyttig med Cron jobs på Linux, som skal gjøre en bestemt oppgave til et bestemt tidspunkt. Som webutvikler bruker jeg dette verktøyet jevnt og trutt, for eksempel dersom jeg ønsker å kjøre en PHP-fil hver midnatt. Men hva med Windows?

På Windows har vi noe som heter «Planlagte oppgaver» (eng: Scheduled Tasks) som er så og si ekvivalent med Cron, men det er ikke så veldig utbredt å bruke. I hvertfall brukte jeg endel tid på å finne ut at dette var et brukbart verktøy!

Wget er også et Linuxprogram, og brukes til å besøke en nettjener (webserver) og hente informasjon derfra.  Heldigvis er dette gjort tilgjengelig for Windows, og er nesten identisk med Linuxversjonen.

  1. Last ned siste versjon av Wget
  2. Kopier innholdet i zip-filen til for eksempel C:\wget\

Nå som wget er på plass, trenger vi bare kjøre en kommando i kommandolinjen til Windows (Start -> Kjør -> cmd.exe). Denne starter den planlagte oppgaven vår, hvor vi setter de ulike parameterene for oppgaven.

I CMD limer du inn følgende:

schtasks /create /tn «Windows Cronjob» /tr «c:\utils\wget\wget.exe -O – -q -t 1 http://example.com/cron.php» /sc hourly

Her oppretter vi oppgaven «Windows Cronjob» som skal kjøre programmet Wget (plassert C:\utils\wget\ hos meg) med argumentene: «-O – -q -t 1 http://example.com/cron.php». Det betyr simpelthen at den skal besøke cron.php som ligger på domenet example.com. Oppgaven skal også utføres hver time.

Det var dét! Så enkelt kan det faktisk gjøres; og det fungerer fint. Kjekt «triks» å kunne dersom du utvikler på en Windowsmaskin.

Sikkerhet i PHP gjort lettere

| 5 kommentarer »

Når du utvikler en nettside, enten det er en applikasjon, rammeverk, bibliotek — hva som helst — er det desidert viktigste sikkerhet. Likevel er det mange som tar snarveier, og slurver seg unna. Om du vil unngå å stå med skjegget i postkassen den dagen du blir angrepet via XSS, CSRF eller SQL injections bør du følge med nå.

Hvorfor?

Du skal aldri stole på brukerne dine. Selv om det er familien eller vennene dine. Årsaken er at enkelte personer kan utnytte sårbarhetene i systemet ditt, som kan resultere i at sensitiv informasjon blir samlet, slettet eller endret. Det kan resultere i at noen tar fysisk kontroll over nettsiden din.

Hva kan man gjøre?

Ved å følge prinsippet ovenfor, må du sørge for å validere all data du skal hente inn fra brukerne. Du bør også sanitere data.

Validering: sjekke om data er av riktig type, for eksempel en ordentlig E-postadresse eller postnummer.
Sanitering: manipulasjon av data, som for eksempel å fjerne enkelte tegn/bokstaver/tall og så videre.

I PHP får vi tilgang til brukerdata via super-globalene $_GET, $_POST, $_COOKIE, $_SERVER og $_SESSION.

Her kan brukere bokstavelig talt skrive hva de vil, og det kan betyr store følger om du ikke sjekker dataene ordentlig.

Løsningen

Jeg har skrevet et bibliotek i PHP kalt «PHP Security Wrapper«. Dette biblioteket tar seg av brukerdata fra GET, POST, SERVER og COOKIE, samtidig som du får muligheten til både å validere og sanitere dem.

Biblioteket er selvfølgelig gratis, og oppdateres hyppig. Om du ønsker å lære mer om dette biblioteket kan du lese forumtråden jeg postet på Norsk Webforum, sjekke ut nettsiden og lese dokumentasjonen.

Det er ikke meningen at dette blogginnlegget skulle ta for seg hvordan du kan sikre deg mot angrep, men om du ønsker å lese videre på emnet kan du sjekke ut følgende linker:

Yr.no – vise værdata direkte på nettsiden din

| Ingen kommentarer »

Siden den norske nettbaserte værtjenesten Yr.no frigir sine værdata gratis, er det mange som er i stand til å vise været fra sin hjembygd på nettsidene sine. Men hvordan gjør dem det?

Jeg skrev for en stund tilbake siden en PHP-klasse som gjorde akkurat dette: hentet frem værdata basert på et norsk postnummer.

Funksjonen mellomlagrer værdataene i ti minutter, slik at belastningen på Yrs servere skal minimeres, og at lastetiden hos brukeren skal oppleves raskere.

Kort fortalt er det kun fem linjer med kode du bør konsentrere deg om:

define ('PATH_WEATHER_ICONS', 'img/weather/');
define ('PATH_CACHE', 'cache/');
define ('CACHE_EXPIRATION', 600);
// How many days we are going to show
define ('DAYS_TO_SHOW', 3);

// The Zip code to which place we will fetch information about
// Defaults to 5440
$zip = isset ($_GET['zip']) ? intval ($_GET['zip']) : 5440;

Først av alt må du fortelle hvilken mappe bilde-ikonene ligger i, og hvor PHP-klassen skal mellomlagre dataene. Deretter spesifiserer du hvor lenge dataene skal bli mellomlagret (600 sekunder = 10 minutter), samt hvor mange dager fremover i tid du skal vise.

Sist, men ikke minst må du spesifisere fra hvor du skal hente værdata fra. Du må endre «5440″ til det postnummeret du vil scriptet skal vise ved default. Dersom du vil se værdata fra et annet postnummer, skriver du følgende i adressefeltet:

index.php?zip=<nytt postnummer her>

Laste ned

PHP-klassen er tilgjengelig via tillegg.yr.no, og er som vanlig lisensiert under Creative Commons.

Tips

Du kan meget lett integrere PHP-klassen min med databasesettet mitt over alle norske postnummer. Slik kan du også finne ut om postnummeret brukeren ønsker å vise, faktisk finnes. Mer informasjon om databasesettet finner du i egen artikkel.

Tilbakemeldinger

Som vanlig setter jeg pris på tilbakemeldinger, som du kan dele i kommentarfeltet!