Mysql
 sql >> база данни >  >> RDS >> Mysql

php как да свържете файл от файлов сървър с тази информация от базата данни

Реших, че ще напиша кратък (за мен това е кратък) „отговор“, само за да мога да обобщя точките си.

Някои „най-добри практики“ при създаване на система за съхранение на файлове. Съхранението на файлове е широка категория, така че пробегът ви може да варира за някои от тях. Приемете ги просто като предложение за това, което открих, работи добре.

Имена на файлове Не съхранявайте файла с името, дадено от краен потребител. Те могат и ще използват всякакви скапани герои, които ще направят живота ви нещастен. Някои могат да бъдат толкова лоши, колкото ' единични кавички, което в Linux по същество прави невъзможно четенето или дори изтриването на файла (директно). Някои неща могат да изглеждат прости като пространство, но в зависимост от това къде го използвате и операционната система на вашия сървър, можете да завършите с one%20two.txt или one+two.txt или one two.txt което може или не може да създаде всякакви проблеми във вашите връзки.

Най-доброто нещо, което трябва да направите, е да създадете хеш, нещо като sha1 това може да бъде толкова просто като {user_id}{orgianl_name} Потребителското име намалява вероятността от сблъсъци с имена на файлове на други потребители.

Предпочитам да правя file_hash('sha1', $contents) по този начин, ако някой качи един и същ файл повече от веднъж, можете да го хванете (съдържанието е същото, хешът е същият). Но ако очаквате да имате големи файлове, може да искате да направите някаква сравнителна оценка върху него, за да видите какъв тип производителност има. Обработвам предимно малки файлове, така че работи добре за това.-забележете- че с времевата марка файлът все още може да бъде запазен, защото пълното име е различно, но го прави доста лесен за виждане и може да бъде проверен в базата данни.

Независимо от това, което правите, бих го поставил с префикс за време time().'-'.$filename . Това е полезна информация, която трябва да имате, защото това е абсолютният час на създаване на файла.

Що се отнася до името, което потребителят дава на файла. Просто запазете това в записа на базата данни. По този начин можете да им покажете името, което очакват, но използвайте име, за което знаете, че винаги е безопасно за връзки.

$filename ='някакъв глупав^ 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";

Изходи

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

Можете да го изпробвате тук

Пътеки никога не съхранявайте пълния път до файла. Всичко, от което се нуждаете в базата данни, е хешът от създаването на хешираното име. "Root" пътеката към папката, в която се съхранява файлът, трябва да се направи в PHP. Това има няколко предимства.

  • предотвратява прехвърлянето на директория. Тъй като не преминавате нито една част от пътя наоколо, не е нужно да се притеснявате толкова, че някой ще подхлъзне \..\.. там и отиват на места, на които не трябва. Слаб пример за това би бил някой, който презаписва .htpassword файл, като качите файл с име това с напречна директория в него.
  • Има по-еднородни изглеждащи връзки, еднакъв размер, еднакъв набор от знаци.

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

  • Поддръжка. Пътищата се променят, сървърите се променят. Изискванията към вашата система се променят. Ако трябва да преместите тези файлове, но сте съхранили абсолютния пълен път до тях в DB, ​​вие сте залепнали, залепвайки всичко заедно с symlinks или актуализиране на всичките ви записи.

Има някои изключения от това. Ако искате да ги съхранявате в месечна папка или чрез потребителско име. Можете да запишете тази част от пътя в отделно поле. Но дори и в този случай можете да го изградите динамично въз основа на данни, записани в записа. Открих, че е най-добре да запазя възможно най-малко информация за пътя. И те създават конфигурация или константа, която можете да използвате на всички места, от които се нуждаете, за да поставите пътя до файла.

Също така path и link са много различни, така че като запазите само името, можете да го свържете с всяка PHP страница, която искате, без да се налага да изваждате данни от пътя. Винаги ми е било по-лесно да добавям към името на файла, отколкото да изваждам от път.

База данни (само някои предложения, употребата може да варира) Както винаги с данните, попитайте се кой, какво, къде, кога

  • id - int автоматично увеличение на първичния ключ
  • user_id - int външен ключ, кой качих го
  • хеш - char[40] *sha1*, unique какво хеша
  • хаш име - varchar {timestampl}-{hash}.{ext} къде името на файловете на твърдия диск
  • име на файл - varchar оригиналното име, дадено от потребителя, по този начин можем да им покажем името, което очакват (ако това е важно)
  • състояние - enum[public,private,deleted,pending.. etc] състоянието на файла, в зависимост от вашия случай на употреба, може да се наложи да прегледате файловете или може би някои са частни, само потребителят може да ги види, може би някои са публични и т.н.
  • status_date - timestamp|datetime време, когато състоянието е променено.
  • create_date - timestamp|datetime кога когато файлът е създаден, се предпочита времеви печат, тъй като улеснява някои неща, но в този случай трябва да се използва същото клеймо за време в хеш името.
  • тип - varchar - тип MIME, може да бъде полезен за настройка на типа MIME при изтегляне и др.

Ако очаквате различни потребители да качат един и същ файл и използвате file_hash можете да направите hash поле комбиниран уникален индекс на user_id и hash по този начин би бил конфликт само ако същият потребител качи същия файл. Можете също да го направите въз основа на клеймото за време и хеша, в зависимост от вашите нужди.

Това са основните неща, за които можех да се сетя, това не е абсолютно, просто някои области, които смятах, че ще бъдат полезни.

Полезно е хешът да има сам, ако го съхранявате самостоятелно, можете да го съхранявате в CHAR(40) за sha1 (заема по-малко място в DB след това VARCHAR ) и задайте съпоставянето на UTF8_bin което е двоично. Това прави търсенията в него чувствителни към главни букви. Въпреки че има малка възможност за сблъсък на хеш, това добавя само малко повече защита, тъй като хешовете са главни и малки букви.

Винаги можете да създадете hashname в движение, ако съхранявате разширението и клеймото за време отделно. Ако откриете, че създавате неща отново и отново, може просто да искате да го съхраните в DB, ​​за да опростите работата в PHP.

Харесва ми просто да поставям хеша във връзката, без разширение, нищо, така че връзките ми изглеждат така.

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

Истински прост, истински общ, безопасен в URL адреси, винаги с един и същ размер и т.н..

hashname за този "файл" ще бъде така

1511848005-ad87109bfff0765f4dd8cf4943b04d16a4070fea.jpg

Ако имате конфликти със същия файл и различен потребител (което споменах по-горе). Винаги можете да добавите частта за времеви отпечатък към връзката, user_id или и двете. Ако използвате user_id, може да е полезно да го поставите наляво с нули. Например някои потребители може да имат ID:1 а някои може да са ID:234 така че можете да го оставите на 4 места и да ги направите 0001 и 0234 . След това добавете това към хеша, който е почти незабележим:

1511848005-ad87109bfff0765f4dd8cf4943b04d16a4070fea0234.jpg

Важното тук е, че защото sha1 винаги е 40 и идентификаторът винаги е 4 можем да разделим двете точно и лесно. И по този начин все още можете да го търсите уникално. Има много различни опции, но много зависи от вашите нужди.

Достъп Като изтегляне. Винаги трябва да извеждате файла с PHP, не им давайте директен достъп до файла. Най-добрият начин е да съхранявате файловете извън уеб корена (над public_html , или www папка). След това в PHP можете да настроите заглавките на правилния тип и основно да прочетете файла. Това работи за почти всичко, с изключение на видео. Не се занимавам с видеоклипове, така че това е тема извън моя опит. Но смятам, че е най-добре да го мисля, тъй като всички файлови данни са текст, а заглавките, които превръщат този текст в изображение, или файл на excel или pdf.

Голямото предимство да не им предоставяте директен достъп до файла е, че ако имате сайт за членство, ако не искате съдържанието ви да е достъпно без вход, можете лесно да проверите в PHP дали са влезли, преди да им дадете съдържанието. И тъй като файлът е извън уеб корена, те нямат достъп до него по друг начин.

Най-важното нещо е да изберете нещо последователно, което все още е достатъчно гъвкаво, за да се справи с всичките ви нужди.

Сигурен съм, че мога да измисля още, но ако имате някакво предложение, не се колебайте да коментирате.

ОСНОВЕН ПОТОК НА ПРОЦЕСА

  1. Потребителят изпраща формуляр (enctype="multipart/form-data" )

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

  1. Сървърът получава публикацията от формуляра Super Globals $_POST и $_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. Проверете за грешки if(!$_FILES['fielname']['error'])

  2. Почистете екранното име $filename = htmlentities($str, ENT_NOQUOTES, "UTF-8");

  3. Запазете файла, създайте DB запис ( PSUDO-CODE )

Като това:

 $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 -качен-файл.php

  1. Създайте връзка ( варира в зависимост от маршрута ), лесният начин е да направите връзката си по този начин http://www.example.com/download?file={$hash} но е по-грозен от http://www.example.com/download/{$hash}

  2. потребителят щраква върху връзката, отива към страницата за изтегляне.

вземете INPUT и потърсете запис

$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

И т.н....

Наздраве!




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Низът е извън индекс с SQL разработчик

  2. задайте нова стойност за ft_min_word_len FULLTEXT в mysql

  3. Пребройте броя на появяванията на низ в поле VARCHAR?

  4. PreparedStatement хвърля синтактична грешка

  5. mysqli_stmt::bind_param() [mysqli-stmt.bind-param]:Броят на променливите не съвпада с броя на параметрите