Въведение в PHP потоци. Информационен портал за сигурност Създаване на нишка php postid

Въведение в PHP потоци. Информационен портал за сигурност Създаване на нишка php postid

Една от най-важните и популярни задачи в PHP е прехвърлянето на данни. Вероятно сте попадали на URL като този повече от веднъж site.ru/page.php?id=114841или форма с полета за въвежданетекст (регистрация, нов коментар и др.). В този и следващите уроци ще говорим за предаване на данни към PHP.

POST метод в PHP

Методът се състои от две части: HTML с форма и полета и PHP манипулатор файл.

внимание! За да работим, ние просто трябва да създадем съответно само два файла.

Демонстрация Изтегляне на източници
Нека да разгледаме пример с коментари - прилагане на потребителско разрешение на сайта:

HTML код(файл post.html)



Форма





Вашият вход:

Твоята парола:





Сега повече за методите за прехвърляне на данни. Има два вида GET (чрез url, отворен - можете да промените url ръчно) и POST (чрез формуляр, затворен). Разликата ще бъде в съдържанието на адресната лента, тоест url.

При получаване на данни, прехвърлени по един от тези начини, данните се събират в масив от типа, съответстващ на метода ($_GET или $_POST). Има и масив, наречен $_REQUEST, който може да съдържа както $_GET, така и $_POST едновременно. Но това е за други примери. Препоръчвам да предавате повечето данни чрез метода POST.

Сега нека да разгледаме кода на манипулатора.

PHP код(във файл test_reg.php)

$login = $_POST["влизане"]; // приема данни, изпратени чрез POST
$pass = $_POST["pass"]; // login и pass са имената на полетата за въвеждане

If (($login == "Admin") && ($pass == "Pass"))
echo "Здравей, Админ! Днес кафе ли е или чай?)";
else echo "Въведохте неправилна комбинация за влизане и парола. Опитайте отново Назад";
?>
Можете да видите как записваме стойностите на полетата със съответното име в масива $_POST в отделни променливи, въпреки че може да се събира и в $_REQUEST.

В манипулатора, може би, ще изработим условието за оторизация - дали данните за вход и парола във формуляра съвпадат с нашата фиктивна (съответно Admin и Pass). И ние или поздравяваме входящия човек (Здравей, Админ! Има ли кафе или чай днес?), или не (Въвели сте грешна комбинация за влизане и парола. Опитайте отново). Въпреки това, за да създадете пълноценно разрешение, все още трябва да се запознаете с бисквитките, сесиите и . Но повече за това по-късно.

Директно в скрипта можете да обработвате данните, както желаете: добавяне, изтриване, криптиране и т.н. Основното е да знаете името на променливата (зададена в HTML формата) и след това да ги съберете с помощта на масивите $_POST, $_GET и $_REQUEST.

Благодаря за вниманието!

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

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

Многонишковостта е възможна в php

Да, можете да правите многопоточност в PHP с помощта на pthreads

От документацията на PHP:

pthreads е обектно-ориентиран API, който предоставя всички инструменти, необходими за многопоточност в PHP. PHP приложенията могат да създават, четат, пишат, изпълняват и синхронизират с Threads, Workers и Threaded.

Внимание. Разширението pthreads не може да се използва в среда на уеб сървър. Следователно нишките в PHP трябва да останат в базирани на CLI приложения.

Прост тест

#!/usr/bin/phparg = $arg; ) публична функция run() ( if ($this->arg) ( $sleep = mt_rand(1, 10); printf("%s: %s -start -sleeps %d" . "\n", date(" g:i:sa"), $this->arg, $sleep); sleep($sleep); printf("%s: %s -finish" . "\n", date("g:i:sa" ), $this->arg); ) ) ) // Създаване на масив $stack = array(); //Иницииране на множество нишки foreach (range("A", "D") като $i) ( $stack = new AsyncOperation($i); ) // Стартиране на нишките foreach ($stack като $t) ( $t- >start(?>).

Първо състезание

12:00:06pm: A -начало -спи 5 12:00:06pm: B -начало -спи 3 12:00:06pm: C -начало -спи 10 12:00:06pm: D -начало -спи 2 12: 00:08pm: D -финал 12:00:09pm: B -финал 12:00:11pm: A -финал 12:00:16pm: C -финал

Второ бягане

12:01:36pm: A -начало -спи 6 12:01:36pm: B -начало -спи 1 12:01:36pm: C -начало -спи 2 12:01:36pm: D -начало -спи 1 12: 13:37: B - финал 12:01:37: D - финал 12:01:38: C - финал 12:01:42: A - финал

Пример от реалния свят

Error_reporting(E_ALL); клас AsyncWebRequest разширява Thread ( public $url; public $data; public function __construct($url) ( $this->url = $url; ) public function run() ( if (($url = $this->url)) ( /* * Ако се иска голямо количество данни, може да искате да * fsockopen и да четете, като използвате usleep между четенията */ $this->data = file_get_contents($url); ) else printf("Тех #%lu не беше предоставен URL\n", $this->getThreadId()); ) ) $t = microtime(true); $g = ново AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10)); /* стартиране на синхронизация */ if ($g->start()) ( printf("Заявката отне %f секунди за стартиране ", microtime(true) - $t); while ($g->isRunning()) ( echo "."; usleep(100); if ($g->join()) ( printf(" и %f секунди за завършване на получаването на %d байта\n", microtime(true) - $t, strlen($g - >data)); else printf(" и %f секунди за завършване, заявката е неуспешна\n", microtime(true) - $t);

защо не използваш popen?

За ($i=0; $i<10; $i++) { // open ten processes for ($j=0; $j<10; $j++) { $pipe[$j] = popen("script2.php", "w"); } // wait for them to finish for ($j=0; $j<10; ++$j) { pclose($pipe[$j]); } }

Threading не е наличен в наличния PHP, но едновременното програмиране е възможно с помощта на HTTP заявки под формата на асинхронни извиквания.

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

Не забравяйте да проверите правилния идентификатор на сесията, например:

http://localhost/test/verifysession.php? sessionid = [валиден идентификатор]

startprocess.php

$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $request); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 1); curl_exec($ch); curl_close($ch); echo $_REQUEST["PHPSESSID"];

process1.php

set_time_limit(0); if ($_REQUEST["sessionid"]) session_id($_REQUEST["sessionid"]); функция checkclose() ( глобален $_SESSION; if ($_SESSION["closesession"]) ( unset($_SESSION["closesession"]); die(); ) ) while(!$close) ( session_start(); $_SESSION ["тест"] = rand(); session_write_close(); if ($_REQUEST["sessionid"]) session_id($_REQUEST["sessionid"]); функция checkclose() ( глобален $_SESSION; if ($_SESSION["closesession"]) ( unset($_SESSION["closesession"]); die(); ) ) while(!$close) ( session_start(); $_SESSION ["тест"] = rand(); session_write_close(); if ($_REQUEST["sessionid"]) session_id($_REQUEST["sessionid"]); функция checkclose() ( глобален $_SESSION; if ($_SESSION["closesession"]) ( unset($_SESSION["closesession"]); die(); ) ) while(!$close) ( session_start(); $_SESSION ["тест"] = rand(); session_write_close();

verifysession.php

if ($_REQUEST["sessionid"]) session_id($_REQUEST["sessionid"]); session_start(); var_dump($_SESSION);

closeprocess.php

if ($_REQUEST["sessionid"]) session_id($_REQUEST["sessionid"]); session_start(); $_SESSION["closesession"] = вярно; var_dump($_SESSION);

Въпреки че не можете да правите нишки, вие имате известна степен на контрол върху процеса в php. Ето два полезни комплекта:

Функции за контрол на процеси http://www.php.net/manual/en/ref.pcntl.php

Можете да разклоните вашия процес с помощта на pcntl_fork - върнете PID на детето. След това можете да използвате posix_kill, за да използвате този PID.

Въпреки това, ако убиете родителския процес, трябва да бъде изпратен сигнал до дъщерния процес, който му казва да умре. Ако самият php не разпознае това, можете да регистрирате функция, за да го контролирате и да направите чист изход с помощта на pcntl_signal.

Можете да симулирате нишки. PHP може да стартира фонови процеси чрез popen (или proc_open). Тези процеси могат да бъдат комуникирани чрез stdin и stdout. Разбира се, тези процеси могат да бъдат php програма. Това вероятно е възможно най-близо до вас.

Можете да използвате exec(), за да изпълните скрипт от командния ред (като командния ред на php) и ако прикачите изхода към файл, вашият скрипт няма да изчака изпълнението на командата.

Не мога да си спомня синтаксиса на php CLI, но имате нужда от нещо като:

Exec("/path/to/php -f "/path/to/file.php" | "/path/to/output.txt"");

Мисля, че няколко споделени хостинг сървъра имат exec() деактивиран по подразбиране от съображения за сигурност, но може би си струва да опитате.

В зависимост от това, което се опитвате да направите, можете също да използвате curl_multi, за да го постигнете.

Той поддържа двупосочна комуникация между нишки и също така има вградена защита за убиване на дъщерни нишки (предотвратяване на осиротели).

Може да имате опция:

  1. multi_curl
  2. Можете да използвате системната команда за същото
  3. Идеалният сценарий е да създадете функция за стрийминг в C и да компилирате/настроите в PHP. Тази функция вече ще бъде PHP функция.

Какво ще кажете за pcntl_fork?

вижте нашата man страница за примери: PHP pcntl_fork

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

Класът Thread е наличен от PECL pthreads ≥ 2.0.0.

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

В своята практика уебмастърите често трябва да използват софтуерни роботи, които извършват редовни или масови заявки за уеб страници, попълване на регистрационни форми или извършване на други подобни действия. Традиционно и съвсем оправдано за целта се използват езикът PHP и библиотеката cURL, които са инсталирани на почти всички уеб сървъри. Библиотеката cURL по същество е наслагване върху сокети и е просто удобна за използване услуга за генериране на http заявка в зависимост от зададените параметри на програмиста.

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

Преди да започнем да описваме механизма за разработване на скриптове, първо ни уведомете какво имам предвид под многопоточност. Въпросът тук е, че всъщност няма многопоточност в PHP и когато терминът „ многопоточност» по отношение на cURL библиотеката, за която говорим множество заявки.

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

Бих искал веднага да отбележа, че инструментите за работа с многопоточност в cURL са много оскъдни, но дори и с тези, които са налични, можете да организирате пълноценна работа с многозаявки.

И така, сега относно практиката... Нека разгледаме пример, когато трябва да изтеглите голям брой уеб страници, за да например проверите наличието на код за обратна връзка върху тях. За да направите това, ще ви трябва следното:

1. Поставете списъка с всички URI в масив
2. Създайте масив от „обикновени“ cURL адреси в необходимото количество (брой нишки) и един cURL_multi
3. Инициализирайте всеки създаден cURL (URL от предварително подготвения масив, публикувайте променливи, ако е необходимо, проксита и т.н.)
4. Добавете всеки cURL към cURL_multi
5. Стартирайте всички нишки, като използвате извикването cURL_multi
6. В цикъла проверяваме състоянието на cURL_multi и ако има завършена нишка, обработваме получената страница и стартираме нов cURL на нейно място. Ако списъкът с URI е приключил, ние обработваме само резултата. Цикълът продължава, докато има поне една незавършена нишка.
7. Затворете всички cURL.

Сега, всъщност, скриптът, който изпълнява тази операция:

    функция Parse(&$urls,$flowcount) (

    // $urls - масив с URL адреси

    // $flowcount - брой нишки

    //Стартиране на нишки

    $ch = масив ();

    $lcount0 =брой($urls);

    if ($flowcount >$lcount0 ) $flowcount =$lcount0 ;

    за ($flow =0 ;$flow<$flowcount ;$flow ++) $ch =curl_ini(array_pop ($urls ) ) ; //създаване на cURL масив

    $mh =curl_multi_init() ; //създаване на cURL_multi

    за ($flow =0 ;$flow<$flowcount ;$flow ++) { //В този цикъл cURL се инициализира

    curl_setopt($ch [ $flow],CURLOPT_REFERER,‘TESTREFERER’);

    curl_setopt($ch [ $flow],CURLOPT_USERAGENT,” );

    curl_setopt($ch [ $flow],CURLOPT_RETURNTRANSFER,1) ;

    curl_setopt($ch [ $flow],CURLOPT_POST,1) ;

    curl_setopt($ch [ $flow],CURLOPT_POSTFIELDS,‘TEST=TESTVAR’) ;

    curl_setopt($ch [ $flow],CURLOPT_COOKIE,‘TEST=TESTCOOKIE’);

    curl_multi_add_handle($mh,$ch [$flow]);

    $flows =null;

    направи ( //Основният цикъл продължава, докато има поне една работеща нишка

    направете curl_multi_exec($mh,$flows); докато ($flows ==$flowcount) ; //циклично проверява броя на изпълняваните нишки

    $info =curl_multi_info_read($mh) ;

    if (!count ($urls) ) ( //Няма повече URL адреси за обработка

    curl_close($info [ 'handle' ] );

    $flowcount –;

    ) иначе ( //Все още има URL за обработка

    curl_setopt($info [ 'handle' ] ,CURLOPT_URL,array_pop ($urls ) ) ;

    $res =curl_multi_getcontent($info [ 'handle' ] ) ;

    curl_multi_remove_handle($mh,$info ['handle']);

    В текста на кода има достатъчно коментари, за да разберем какво се случва. Нека изясня няколко точки...

    1. Извикването на curl_multi_init трябва да бъде направено, след като всички „обикновени“ cURL са инициализирани, т.е. Невъзможно е да се разменят 9-ти и 10-ти ред, така че секциите с код за инициализиране на $ch и задаване на необходимите параметри са разделени.

    2. Всеки път, когато curl_multi_exec се извиква на ред 22, променливата $flows се настройва на броя на активните нишки, който след това се сравнява с броя на изпълняваните нишки (променливата $flowcount ще бъде намалена, ако няма повече записи в списък с URL адреси за обработка (масивът $urls).

    3. curl_multi_info_read връща информация за следващата обработена нишка или false, ако не е имало промени от предишното извикване на тази функция.

    4. Функцията curl_multi_info_read актуализира данните, поставени в променливата $info, само след като се изпълни curl_multi_exec, така че и двете функции трябва да се използват за обработка на всяка нишка.

    5. За да добавите нова нишка, трябва последователно да извикате три функции: curl_multi_remove_handle, curl_multi_add_handle и curl_multi_exec.

    И последно нещо: понякога е важно да знаете някаква допълнителна информация, свързана с потока, който се обработва. В този случай можете да създадете асоциативен масив, чиито ключове ще бъдат идентификаторите на нишките, т.е. стойности в $info['handle'].

В програмирането постоянно трябва да работите с различни ресурси: файлове, сокети, http връзки. И всички те имат някакъв вид интерфейс за достъп, често несъвместими един с друг. Ето защо, за да се премахнат тези несъответствия и да се обедини работата с различни източници на данни, като се започне с PHP 4.3са изобретени PHP Streams - потоци.

Макар че PHP 4.3излезе отдавна, мн PHP програмистиимам много бегла представа за нишки в PHP, и продължете да използвате КЪДРИЦАнавсякъде, макар и в PHPВъв формата има по-удобна алтернатива за това Контекст на потока.

Съществуват следните типове потоци PHP:

  • Файл на твърд диск;
  • HTTP връзкас уебсайт;
  • Съединение UDPсъс сървъра;
  • ZIP файл;
  • файл * .mp3.

Какво е общото между всички тези ресурси? Всички те могат да се четат и пишат, т.е. операциите за четене и запис могат да се прилагат към всички тях. Сила PHP потоциНомерът е, че можете да получите достъп до всички тези ресурси, като използвате един и същ набор от функции. Много е удобно. Освен това, ако внезапно възникне такава необходимост, можете да напишете своя собствена реализация на манипулатора на нишки "обвивка на поток". В допълнение към четенето и писането, потоци в PHPсъщо ви позволява да извършвате други операции като преименуване и изтриване.

Програмирането е включено PHP, Вече сте срещали теми, въпреки че може да не сте го осъзнали. И така, функциите, които работят с потоци, са fopen(), file_get_contents(), файл ()и т.н. Така че всъщност вие вече използвате файлови потоци през цялото това време, напълно прозрачно.

За да работите с друг тип поток, трябва да посочите неговия протокол (обвивка)по следния начин: обвивка // някакъв_поток_ресурс, Където обвивка //- това е напр http://, файл://, ftp://, zip://и т.н., и някакъв_поток_ресурс - URI, идентифицира какво искате да отворите. URIне налага никакви ограничения върху формата. Примери:

  • http://site/php-stream-introduction.html
  • file://C:/Projects/rostov-on-don.jpg
  • ftp://user:password@test.com/pub/file.txt
  • mpeg://file:///music/song.mp3
  • data://text/plain;base64,SSBsb3ZlIFBIUAo=

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

// списък на регистрираните транспортни сокети
print_r(stream_get_transports());

// списък с регистрирани нишки (манипулатори)
print_r(stream_get_wrappers());

// списък на регистрираните филтри
print_r(stream_get_filters();

Контексти на PHP нишки

Често има нужда да посочите допълнителни параметри, когато правите http заявка. Контекстите на нишките решават този проблем, като ви позволяват да зададете допълнителни параметри. Много функции, съобразени с нишката, имат незадължителен контекстен параметър на нишката. Нека да разгледаме функцията file_get_contents():

String file_get_contents(низ $filename [, int $flags = 0 [, resource $context [, int $offset = -1 [, int $maxlen = -1]]]])

Както можете да видите, контекстът на нишката се предава като трети параметър. Контекстите се създават с помощта на функцията stream_context_create(), който приема масив и връща контекстен ресурс.

$опции = масив(
"http" => масив(
"method" => "GET",
"header" => "Accept-language: en\r\n".
"Бисквитка: foo = лента\r\n"
);

$context = stream_context_create($options);

// Използване на това с file_get_contents ...
echo file_get_contents("http://www.example.com/", 0, $context);

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

Преглеждания: 1256

Наскоро пробвах pthreads и бях приятно изненадан - това е разширение, което добавя възможност за работа с множество реални нишки в PHP. Без емулация, без магия, без фалшификати - всичко е истинско.



Обмислям такава задача. Има набор от задачи, които трябва да бъдат изпълнени бързо. PHP има други инструменти за решаване на този проблем, те не са споменати тук, статията е за pthreads.



Какво представляват pthreads

Това е всичко! Е, почти всичко. Всъщност има нещо, което може да разстрои любознателния читател. Нищо от това не работи на стандартен PHP, компилиран с опции по подразбиране. За да се насладите на многопоточност, трябва да имате активиран ZTS (Zend Thread Safety) във вашия PHP.

Настройка на PHP

След това PHP със ZTS. Не обръщайте внимание на голямата разлика във времето за изпълнение в сравнение с PHP без ZTS (37,65 срещу 265,05 секунди), не се опитвах да обобщавам настройката на PHP. В случая без ZTS имам активиран XDebug например.


Както можете да видите, когато използвате 2 нишки, скоростта на изпълнение на програмата е приблизително 1,5 пъти по-висока, отколкото в случая на линеен код. При използване на 4 нишки - 3 пъти.


Можете да отбележите, че въпреки че процесорът е 8-ядрен, времето за изпълнение на програмата остава почти непроменено, ако се използват повече от 4 нишки. Изглежда, че това се дължи на факта, че процесорът ми има 4 физически ядра. За по-голяма яснота съм изобразил табелата под формата на диаграма.


Резюме

В PHP е възможно да се работи доста елегантно с многопоточност, като се използва разширението pthreads. Това дава забележимо увеличение на производителността.

изгледи