sql >> Databasteknik >  >> RDS >> Mysql

php hur man länkar en fil från filservern till den informationen från databasen

Jag tänkte att jag skulle skriva ett kort (för mig är detta kort) "svar" bara så att jag kunde sammanfatta mina poänger.

Några "bästa metoder" när du skapar ett fillagringssystem. Fillagring är en bred kategori så din körsträcka kan variera för vissa av dessa. Ta dem bara som ett förslag på vad jag tyckte fungerar bra.

Filnamn Lagra inte filen med det namn som en slutanvändare ger den. De kan och kommer att använda alla typer av skitkaraktärer som kommer att göra ditt liv surt. Vissa kan vara så dåliga som ' enstaka citattecken, vilket på linux i princip gör det så att det är omöjligt att läsa, eller till och med ta bort filen ( direkt ). Vissa saker kan verka enkla som ett utrymme men beroende på var du använder det och operativsystemet på din server kan du sluta med one%20two.txt eller one+two.txt eller one two.txt som kanske skapar alla typer av problem i dina länkar.

Det bästa du kan göra är att skapa en hash, något som sha1 detta kan vara så enkelt som {user_id}{orgianl_name} Användarnamnet gör det mindre sannolikt för kollisioner med andra användares filnamn.

Jag föredrar att göra file_hash('sha1', $contents) på så sätt om någon laddar upp samma fil mer än när du kan fånga det (innehållet är detsamma, hashen är densamma). Men om du förväntar dig att ha stora filer kanske du vill göra lite bänkmarkering på den för att se vilken typ av prestanda den har. Jag hanterar mest små filer så det fungerar bra för det.-observera- att med tidsstämpeln kan filen fortfarande sparas eftersom det fullständiga namnet är annorlunda, men det gör det ganska lätt att se, och det kan verifieras i databasen.

Oavsett vad du gör skulle jag prefixa det med en tidsstämpel time().'-'.$filename . Detta är användbar information att ha, eftersom det är den absoluta tidpunkten då filen skapades.

När det gäller namnet ger en användare filen. Bara lagra det i databasposten. På så sätt kan du visa dem det namn de förväntar sig, men använd ett namn som du vet alltid är säkert för länkar.

$filename ='något skit^ fileane.jpg';

$ext = strrchr($filename, '.');

echo "\nExt: {$ext}\n";

$hash = sha1('some crapy^ fileane.jpg');

echo "Hash: {$hash}\n";

$time = time();

echo "Timestamp: {$time}\n";

$hashname = $time.'-'.$hash.$ext;

echo "Hashname: $hashname\n";

Utgångar

Ext: .jpg
Hash: bb9d2c2c7c73bb8248537a701870e35742b41c02
Timestamp: 1511853063
Hashname: 1511853063-bb9d2c2c7c73bb8248537a701870e35742b41c02.jpg

Du kan prova det här

Vägar lagra aldrig hela sökvägen till filen. Allt du behöver i databasen är hashen från att skapa det hashade namnet. "Root"-sökvägen till mappen som filen är lagrad i bör göras i PHP. Detta har flera fördelar.

  • förhindrar katalogöverföring. Eftersom du inte passerar någon del av stigen runt dig behöver du inte oroa dig lika mycket för att någon ska tappa en \..\.. där och går platser de inte borde. Ett dåligt exempel på detta skulle vara någon som skriver över ett .htpassword fil genom att ladda upp en fil som heter den där katalogen är tvärgående.
  • Har mer enhetliga länkar, enhetlig storlek, enhetlig uppsättning tecken.

https://en.wikipedia.org/wiki/Directory_traversal_attack

  • Underhåll. Vägar förändras, servrar förändras. Kraven på ditt system förändras. Om du behöver flytta dessa filer, men du lagrade den absoluta fullständiga sökvägen till dem i DB:n limmade du ihop allt med symlinks eller uppdatera alla dina poster.

Det finns några undantag från detta. Om du vill lagra dem i en månatlig mapp eller efter användarnamn. Du kan spara den delen av vägen i ett separat fält. Men även i så fall kan du bygga det dynamiskt baserat på data som sparats i posten. Jag har tyckt att det är bäst att spara så lite väginformation som möjligt. Och de gör en konfiguration eller en konstant som du kan använda på alla ställen du behöver för att lägga sökvägen till filen.

Även path och link är väldigt olika, så genom att bara spara namnet kan du länka det från vilken PHP-sida du vill utan att behöva subtrahera data från sökvägen. Jag har alltid tyckt att det är lättare att lägga till filnamnet och sedan subtrahera från en sökväg.

Databas (bara några förslag, användningen kan variera) Som alltid med data fråga dig själv vem, vad, var, när

  • id - int primärnyckel automatisk ökning
  • användar-id - int främmande nyckel, vem laddade upp den
  • hash - char[40] *sha1*, unique vad hashen
  • hashnamn - varchar {timestampl}-{hash}.{ext} var filnamnet på hårddisken
  • filnamn - varchar det ursprungliga namnet som användaren gav, på så sätt kan vi visa dem det namn de förväntar sig (om det är viktigt)
  • status - enum[public,private,deleted,pending.. etc] status för filen, beroende på ditt användningsfall, kanske du måste granska filerna, eller så kanske vissa är privata bara användaren kan se dem, kanske vissa är offentliga osv.
  • status_datum - timestamp|datetime gången statusen ändrades.
  • skapa_datum - timestamp|datetime när tid då filen skapades är en tidsstämpel att föredra eftersom det gör vissa saker enklare men det bör vara samma tidsstämpel som används i hashnamnet, i så fall.
  • typ - varchar - mime-typ, kan vara användbar för att ställa in mime-typ vid nedladdning etc.

Om du förväntar dig att olika användare ska ladda upp samma fil och du använder file_hash du kan göra hash fält ett kombinerat unikt index för user_id och hash på så sätt skulle det bara komma i konflikt om samma användare laddade upp samma fil. Du kan också göra det baserat på tidsstämpeln och hashen, beroende på dina behov.

Det är de grundläggande sakerna jag kunde komma på, det här är inte ett absolut, bara några fält som jag trodde skulle vara användbara.

Det är användbart att ha hashen för sig, om du lagrar den för sig själv kan du lagra den i en CHAR(40) för sha1 (tar upp mindre utrymme i databasen än VARCHAR ) och ställ in sorteringen till UTF8_bin vilket är binärt. Detta gör sökningar på den skiftlägeskänsliga. Även om det finns liten risk för en hashkollision, ger detta bara lite mer skydd eftersom hash är stora och små bokstäver.

Du kan alltid bygga hashname i farten om du lagrar tillägget och tidsstämpeln separat. Om du kommer på dig själv att skapa saker gång på gång kanske du bara vill lagra det i DB för att förenkla arbetet i PHP.

Jag gillar att bara lägga in hashen i länken, ingen förlängning inget något så mina länkar ser ut så här.

http://www.example.com/download/ad87109bfff0765f4dd8cf4943b04d16a4070fea

Riktigt enkelt, riktigt generiskt, säkert i webbadresser alltid samma storlek osv.

hashname för denna "fil" skulle vara så här

1511848005-ad87109bfff0765f4dd8cf4943b04d16a4070fea.jpg

Om du har konflikter med samma fil och annan användare (som jag nämnde ovan). Du kan alltid lägga till tidsstämpeln i länken, user_id eller båda. Om du använder user_id kan det vara användbart att vänster fylla på det med nollor. Till exempel kan vissa användare ha ID:1 och vissa kan vara ID:234 så att du kunde lämna den till fyra platser och göra dem till 0001 och 0234 . Lägg sedan till det i hashen, vilket nästan inte märks:

1511848005-ad87109bfff0765f4dd8cf4943b04d16a4070fea0234.jpg

Det viktiga här är att eftersom sha1 är alltid 40 och id:t är alltid 4 vi kan separera de två exakt och enkelt. Och på så sätt kan du fortfarande slå upp det unikt. Det finns många olika alternativ men så mycket beror på dina behov.

Åtkomst Som att ladda ner. Du bör alltid mata ut filen med PHP, ge dem inte direktåtkomst till filen. Det bästa sättet är att lagra filerna utanför webbroten ( ovanför public_html). eller www mapp ). Sedan i PHP kan du ställa in rubrikerna till rätt typ och i princip läsa upp filen. Detta fungerar för i stort sett allt utom video. Jag hanterar inte videor så det är ett ämne utanför min erfarenhet. Men jag tycker att det är bäst att tänka på det eftersom all fildata är text, det är rubrikerna som gör den texten till en bild, eller en excel-fil eller en pdf.

Den stora fördelen med att inte ge dem direkt tillgång till filen är att om du har en medlemssida, om du inte vill att ditt innehåll ska vara tillgängligt utan en inloggning kan du enkelt checka in PHP om de är inloggade innan du ger dem innehållet. Och eftersom filen ligger utanför webbroten kan de inte komma åt den på något annat sätt.

Det viktigaste är att välja något konsekvent, som fortfarande är tillräckligt flexibelt för att hantera alla dina behov.

Jag är säker på att jag kan komma med mer, men om du har några förslag, kommentera gärna.

GRUNDPROCESSFLÖDE

  1. Användaren skickar in formuläret (enctype="multipart/form-data" )

https://www.w3schools.com/tags/att_form_enctype.asp

  1. Servern tar emot inlägget från formuläret Super Globals $_POST och $_FILES

http://php.net/manual/en/reserved.variables.files .php

$_FILES = [
 'fieldname' => [
        'name' => "MyFile.txt" // (comes from the browser, so treat as tainted)
        'type' => "text/plain" //  (not sure where it gets this from - assume the browser, so treat as tainted)
        'tmp_name' => "/tmp/php/php1h4j1o" // (could be anywhere on your system, depending on your config settings, but the user has no control, so this isn't tainted)
        'error' => "0" //UPLOAD_ERR_OK  (= 0)
        'size' => "123" //   (the size in bytes)
    ]
 ];
  1. Kontrollera om det finns fel if(!$_FILES['fielname']['error'])

  2. Rensa visningsnamnet $filename = htmlentities($str, ENT_NOQUOTES, "UTF-8");

  3. Spara fil, skapa DB-post ( PSUDO-CODE )

Så här:

 $path = __DIR__.'/uploads/'; //for exmaple

$time = time();
$hash = hash_file('sha1',$_FILES['fielname']['tmp_name']);
$type = $_FILES['fielname']['type'];
$hashname = $time.'-'.$hash.strrchr($_FILES['fielname']['name'], '.');
$status = 'pending';

if(!move_uploaded_file ($_FILES['fielname']['tmp_name'], $path.$hashname  )){
     //failed
     //do somehing for errors.
     die();
}


//store record in db

http://php.net/manual/en/function.move -uploaded-file.php

  1. Skapa länk (varierar beroende på routing), det enkla sättet är att göra din länk så här http://www.example.com/download?file={$hash} men det är fulare än http://www.example.com/download/{$hash}

  2. användaren klickar på länken går till nedladdningssidan.

få INPUT och slå upp posten

$hash = $_GET['file'];

$stmt = $PDO->prepare("SELECT * FROM attachments WHERE hash = :hash LIMIT 1");  
$stmt->execute([":hash" => $hash]);

$row = $stmt->fetch(PDO::FETCH_ASSOC);

print_r($row);

http://php.net/manual/en/intro.pdo.php

Osv...

Skål!




  1. Ubuntu - 12.04 - MySql startar inte med att använda tjänsten mysql start

  2. Fel vid försök att installera Django CMS i virtualenv w/ MySQL på Mac OSX

  3. MySQL samtidighet, hur fungerar det och behöver jag hantera det i min applikation

  4. Räkna på varandra följande dubbletter i SQL