Så hanterar du base64 i PHP

» »

Publicerad i PHP den

Metoden base64 används för att konvertera binärdata till ASCII-text, men hur använder man det egentligen? Här går vi igenom konceptet med flera olika exempel.

Oavsett om du utvecklar webbapplikationer i PHP eller om du skriver applikationer i C++, Java eller C# är base64 ett fenomen du antagligen kommer stöta på förr eller senare.

Metoden ger oss möjligheten att skicka och ta emot binärdata som i andra fall innehåller tecken som inte alltid kan visas, och säkerställer därmed en kompatibilitet mellan olika språk och system.

Användningsområden

Binärdata kan bestå av vad som helst, som exempelvis filer, stillbilder eller vanlig text. Det vanligaste användningsområdet är e-postbilagor, som nästan alltid kodas i base64-format när du skickar filer med e-post.

Ett annat populärt användningsområde är just hanteringen av stillbilder på webbplatser, där man istället för att lagra en bild som en fil som man visar upp kan skriva base64-koden direkt som källa i HTML-kodens img-taggar.

Tecken i base64

Det är totalt 64 tecken som finns med i teckenuppsättningen för base64, därav siffran 64 i namnet base64. De tecken som utgör metoden är följande:

  • Små bokstäver (gemener): a-z
  • Stora bokstäver (versaler): A-Z
  • Siffror: 0-9
  • Tecken: + och /

Det totala antalet är alltså 64 stycken, och samtliga av dem går att använda som webbadresser (URL) utan att det blir några problem, som det kan bli med exempelvis tecknen ? eller &, där webbservern förväntar sig parametrar efter.

Skapa en bild från Base64

För att ge ett bra exempel på hur man kan använda och presentera en base64-sträng som en bild kommer vi göra det på det, enligt mig, enklaste sättet; att konvertera den med hjälp av PHP och sedan hantera den som en vanlig bild.

Låt säga att vi har en bild i base64-format i variabeln $imageSource, som vi önskar spara ner lokalt på vår server;

$imageSource = 'data:image/jpeg;base64,/9j/4RifdksfdOWPoklQew0AKgA...';

Vi behöver alltså ta hela strängen, ta fram det binära datat som utgör bilden vi ska arbeta med, konvertera den och slutligen spara ner den.

1. Validera base64-strängen

Till att börja med måste vi se till att den sträng vi ska hantera uppfyller två kriterier;

  1. det är en bild
  2. det är en base64-sträng

Uppfyller strängen inte dessa två kriterier vill vi inte låta PHP börja behandla bilden. Du kan bekräfta detta genom att kontrollera att data:image/ samt base64 finns i strängen på det här sättet;

if (stripos($imageSource,'data:image/'!==false && stripos($imageSource,'base64'!==false) {
    // den kod vi ska skriva nedan
}

Oavsett om det står jpeg, jpg, png, bmp eller gif efter data:image/ har vi iallafall undersökt om texten om att det är en bild samt att det är en base64-sträng finns med.

Det här är inte livsviktigt om man bara ska behandla en bild, men det är generellt oerhört viktigt att ha det som ett mindset när man skriver kod, oavsett i vilket språk eller för vilken applikation.

Tänk alltid på att validera datakällan innan du behandlar den, och även om du — som i vårt fall — sparar ner den lokalt på din server. I allra värsta fall skulle koden annars kunna utnyttjas för att placera exekverbar kod på vår server.

2. Ta fram bildkällan

Det är bra att känna till att bildformatet läggs in i base64-strängen utöver det binära datat för bilden — vilket vi använde för att bekräfta att det är en bild samt en base64-sträng — inte får misstas av din PHP-kod som en del av bilden i sig.

Bildformatet läggs in i början av strängen och sträcker sig fram till kommatecknet i base64-strängen, som du kan se här nedanför:

$imageSource = 'data:image/jpeg;base64,/9j/4RifdksfdOWPoklQew0AKgA...';

Här måste vi alltså ta bort allt som finns innan det första kommatecknet för att komma åt den faktiska bildkällan, vilket vi enkelt kan göra med PHP-funktionen explode() och ett komma som avgränsare;

$imageCode = explode(',',$imageSource)[1];

Funktionen explode() skapar en array med alla strängar på varsin sida om det tecken vi väljer som en avgränsare, i det här fallet ett kommatecken. Eftersom vi i det här exemplet bara har ett kommatecken innebär det att vi får en array med två värden;

  1. texten innan kommatecknet (bildformatet)
  2. texten efter kommatecknet (bildkällan)

Texten innan kommatecknet ger oss i det här fallet information om vilken typ av bild det är (JPEG) och texten efter kommatecknet är den bild vi vill komma åt i base64-format. För att komma åt denna sträng direkt lägger jag [1] efter explode() för att hämta det andra värdet från vår skapade array — en array börjar nämligen på 0 och inte på 1.

Nu har vi alltså vår bildkälla i base64-format i variabeln $imageCode.

3. Avkoda base64 med PHP

Nu kommer vi till det sista steget innan vi har en bild att visa — att konvertera base64-strängen med bildkällan till en bild i PHP. Lyckligtvis finns det färdiga och enkla funktioner för att göra detta, så vi börjar med att avkoda base64-strängen;

$imageContent = base64_decode($imageCode);

Nu har vi kodat av base64-strängen med hjälp av PHP-funktionen base64_decode() och lagt resultatet i variabeln $imageContent.

4. Skapa en bild

Nu har vi den avkodade base64-strängen i variabeln $imageContent, och vill skapa en bild som PHP kan hantera. För att göra detta använder vi PHP-funktionen imagecreatefromstring() på det här sättet;

$image = imagecreatefromstring($imageContent);

Nu har vi skapat en bild som ligger i variabeln $image, och för att säkerställa att det faktiskt har gått bra gör vi sedan en if-sats där vi kollar om $image har värdet false eller ej.

if ($image!==false) {
    // bilden har skapats
}

Om vi vill göra ytterligare kontroller att det är en bild kan du använda funktionerna imagesx() och imagesy(), som ger dig bredden (x) och höjden (y) på din nyskapade bild. Om det skulle vara så att vi misslyckades med att generera en bild med hjälp av imagecreatefromstring() kommer vi heller inte ha någon bredd eller höjd på bilden.

if (imagesx($image)>0) {
    // bilden har bredd
}

Om funktionen imagesx() ger ett positivt värde vet vi att bilden vi har skapat har en bredd, och därmed kan vi vara säkra på att bildkällan är legitim och faktiskt är en bild.

Vi kan även kombinera dem inuti if-satsen genom att skriva && emellan;

if ($image!==false && imagesx($image)>0) {
    // det gick bra, vad vill vi göra med bilden?
}

5. Spara bilden i olika format

Nu har vi avkodat base64-strängen och genererat en bild från den avkodade strängen. Vi kan dessutom vara säkra på att det faktiskt är en bild, eftersom vi har kollat att den har en bredd och inte har misslyckats i skapandet av bilden.

Vad ska vi nu göra med bilden vi har genererat? Antagligen kan vi visa upp den direkt i webbläsaren, vilket vi gör med följande kod:

header('Content-type: image/png');
echo $image;
exit;

Först skickar vi information till webbläsaren om vilken information webbservern skickar med hjälp av funktionen header(), där vi säger att vi levererar en bild i PNG-format. Därefter skriver vi ut den genererade bilden från variabeln $image, och stänger av skriptet med hjälp av exit.

Om vi istället vill spara ner bilden till en fil på webbservern gör vi det med hjälp av funktionerna imagepng(), imagejpeg() eller imagegif(). Vi bestämmer oss för att sökvägen dit vi vill spara filen är följande;

$target = '/var/www/bildtest/bildtest';

Beroende på om vi vill spara ner bilden som PNG eller JPG behöver vi sedan ändra filändelsen till den metod vi väljer.

5.1 Spara till PNG

Formatet PNG ger oss möjligheten att spara en komprimerad bild som inte har en försämrad bildkvalitét — den är alltså inte förstörande i sin komprimering. Detta leder till bättre bildkvalitet och en större filstorlek när vi sparar den, så vi behöver välja vad som passar bäst i sammanhanget.

För att spara ner en fil i PNG-format använder vi funktionen imagepng() på det här sättet:

imagepng($image,$target.'.png');

Eftersom det nu är en PNG-bild vi sparar lägger vi även till filändelsen .png efter filnamnet i variabeln $target, så att vi vet vilket bildformat vi har sparat ner bilden i.

5.2 Spara till JPG

Om vi istället vill spara till JPG, vilket är en komprimeringsmetod som faktiskt ger försämrad bildkvalitet men som avsevärt minskar filstorleken, använder vi funktionen imagejpeg(). Här får vi välja vilken variabel vi har bildkoden i, var vi vill spara den samt i vilken kvalitet vi vill spara den.

Kvaliteten anges som ett värde mellan 1-100 där 1 är sämst kvalitet och 100 är bäst kvalitet (nästan okomprimerat). Standardvärdet för imagejpeg()-funktionens kvalitetsinställning är 75, och jag tycker att 75-80 ger så pass bra resultat att man inte störs av komprimeringen när man tittar på bilderna.

Att spara ner en bild i JPG-format är nästan lika enkelt som med en PNG-bild, förutom kvalitetsinställningen i slutet;

imagejpeg($image,$target.'.jpg',80);

Nu har vi sparat ner en JPG-bild till $target med kvalitetsinställningen 80, som jag oftast använder. Vill man ha bättre kvalitet höjer man till 90, 95 eller 100, men då kommer bilden ta upp mer utrymme på hårddisken.

6. Töm variabeln

Det allra sista steget är att tömma vår variabel $image så att vi inte ligger med onödigt mycket av serverns minne utan anledning. När vi är klara med den bild vi genererat tar vi "sönder" den med hjälp av funktionen imagedestroy();

imagedestroy($image);

I det här exemplet har vi ett långt skript, men om vår PHP-kod hade varit på flera hundra rader och involverat många olika bilder eller funktioner behöver vi faktiskt tänka på hur mycket av serverns minne vi använder.

7. Resultat

Hela skriptet vi har skapat ser nu ut så här:

$imageSource = 'data:image/jpeg;base64,/9j/4RifdksfdOWPoklQew0AKgA...';
$target = '/var/www/bildtest/bildtest';
if (stripos($imageSource,'data:image/'!==false && stripos($imageSource,'base64'!==false) {
    $imageCode = explode(',',$imageSource)[1];
    $imageContent = base64_decode($imageCode);
    $image = imagecreatefromstring($imageContent);
    if ($image!==false && imagesx($image)>0) {
        imagepng($image,$target.'.png');
        imagedestroy($image);
    }
}

Vi har nu tagit en base64-sträng och gjort följande:

  1. validerat att den ser korrekt ut
  2. extraherat bildkällan från hela base64-strängen
  3. avkodat bas64-strängen med base64_decode()
  4. genererat en bild med imagecreatefromstring()
  5. validerat den genererade bildens bredd med imagesx()
  6. sparat ner en PNG-fil med imagepng()
  7. tömt den genererade bilden med imagedestroy()

Inte dåligt, tycker jag — och allt från en lång textsträng i base64-format.

Skapa base64-kod från en bild

Nästa exempel i den här artikeln blir att göra tvärtom, alltså att ta en bild och skapa en base64-kod utifrån detta. Det här blir en betydligt kortare del av artikeln, men minst lika viktig eftersom vi behöver lära oss att hantera base64 åt båda hållen, alltså både avkodning (decode) och kodning (encode).

Om vi tar vår PNG-bild vi har skapat här ovanför hämtar vi upp den med hjälp av file_get_contents() så här;

$imageSource = file_get_contents($target.'.png');

För att sedan konvertera den från den binära bildkälla vi nu har i variabeln $image använder vi base64_encode() för att skapa en base64-sträng av bildkällan;

$imageEncoded = base64_encode($imageSource);

Denna variabel kan vi nu använda som bildkälla direkt i en img-tagg på en HTML-sida, och bilden kan då visas för webbläsaren helt utan att vi sparar ner den och traditionellt hänvisar till en fil i img-taggen;

<html>
    <body>
            <img src="data:image/png;base64,'.$imageEncoded.'">
    </body>
</html>

Fördelen är som sagt att man slipper spara filer på servern, och nackdelen är att det kan bli lite svårt att hantera både cache och prestanda när man gör på det här sättet.

Har man en liten webbplats som man vill behålla "helt i kod" och inte spara ner något så är det dock ett bra sätt att lösa det på.

Slutligen

Att använda base64-strängen som bildkälla underlättar på ett par sätt, men är svårt att optimera för cache både på server och i besökarens webbläsare.

Vill man leverera en webbplats utan några externa filer som bilder eller liknande är det dock ett bra sätt att få med hela innehållet utan externa referenser.

Personligen använder jag inte base64-konverterade strängar till något. Jag lagrar ibland bilder som binärdata i BLOB-format i databaser, men när jag visar dem skriver jag dem till filer istället — det blir enklare både för mig (i mitt huvud alltså) och för servern.


Detaljer

  • Titel: Så hanterar du base64 i PHP
  • Publicerad:
  • Skribent:
  • Kategorier: PHP

Populära inlägg

Här hittar du de mest besökta artiklarna den senaste tiden.

Populära tjänster

Webbhotell

Inleed Special

29 kr / mån

  • Utrymme: 10 GB
  • Trafikmängd: 250 GB
  • Gratis SSL-certifikat: Ja
  • Startavgift: 0 kr

Virtuell server

Inleed VPS #1

199 kr / mån

  • Antal CPU-kärnor: 1 st
  • Minne: 8 GB
  • Utrymme: 100 GB
  • Trafikmängd: 3000 GB

Dedikerad server

Inleed Server #1

499 kr / mån

  • Antal CPU-kärnor: 2 st
  • Minne: 8 GB
  • Utrymme: 500 GB
  • Trafikmängd: 3000 GB

Backuphantering

Inleed Backup 100

19 kr / mån

  • Utrymme: 100 GB
  • Trafikmängd: 3000 GB
  • Startavgift: 0 kr

Domänhantering

Inleed DNS

0 kr / mån

  • Antal domännamn: Obegränsat

Co-location

Inleed Rackserver 1U

299 kr / mån

  • Trafikmängd: 3000 GB
  • Anslutning: 1000 Mbit/s
  • Reservström: UPS + Diesel
  • Startavgift: 0 kr

VPN-tjänster

NordVPN

33 kr / mån

  • Anslutningar: 6 st
Bäst webbhotell just nu
VPN-tjänster Pris Anslutningar
OVPN 49 kr 4 st
Inleed VPN 29 kr 2 st
NordVPN 33 kr 6 st
Ivacy VPN 22 kr 10 st

Vill du ha hjälp?

Ibland kan det vara svårt att göra ett val. Har du fortfarande inte hittat den information du söker, eller undrar du över något som saknas på sidan? Hör av dig till oss så hjälper vi dig!

Kontakta oss