Архив метки: php

Многопоточность в PHP

Ну как известно штатно её нет (с). А иногда очень хочется. Предлагаемая пока альтернатива разработчками — функция Fork() которая по сути создает дочерний процесс, куда передает все открытые соединения, значения переменных и т.п. и продолжает в дочернем процессе с того момента с которого процесс в «родителе» начат.  Один нюанс — при завершении дочернего процесса — все соединения закрываются. Обходить этот нюанс можно посылая сигнал posix_kill(posix_getpid(), SIGHUP);  в дочернем процессе в случае нужды его завершить.

Таким образом «эталонная» реализация «многопоточности» в PHP будет выглядеть примерно так:

какойто код...
какойто код...
//предстоит длительная трудоемкая задача
$child_pid = pcntl_fork();
if ($child_pid==0){
	//длительная ресурсоемкая задача
	echo "--завершил дочерний процесс\n";
	posix_kill(posix_getpid(), SIGHUP);
} else {
	echo "--стартовал дочерний процесс\n";
};

 

A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.

Ходишь-ходишь в школу, а потом «бац — вторая смена»… Эмм я к тому что в 2020 поймать ошибку 2012 года, помеченную на CentOS как «закрытую».. Да еще и на PHP..

А дело вот в чем. На одном из проектов использую WebSocket сервер WorkMan, который имеет псевдомногопотоковость. Внутри потоков, активно использую вызовы curl_exec. Вот они то и вызывают ошибку «A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.«, которая выводится при помощи curl_error. Описание ошибки было еще в далеком 2012 году:  https://bugzilla.redhat.com/show_bug.cgi?id=870856

Помечена как «закрытая». А вот и нет.. Хотя на Ubuntu не воспроизводится — только  «CentOS Linux release 7.8.2003»

Как лечим:

export NSS_STRICT_NOFORK=DISABLED

Генерация случайного имени файла при загрузке на сервере

Для того чтобы сохранить кудато в папку на сервере файл выбранный пользователем, необходимо указать его имя. Чтобы имена точно не повторялись, можно поступить например так:

$answer["error"]=true;
$answer["errortext"]="Ошибка сохранения фото (ошибка доступа)";

$uploaddir = WUO_ROOT.'/uploads'; 
if( ! is_dir( $uploaddir ) ) mkdir( $uploaddir, 0777 );
$uploaddir = WUO_ROOT.'/uploads/'.Date("Y"); 
if( ! is_dir( $uploaddir ) ) mkdir( $uploaddir, 0777 );
$uploaddir = WUO_ROOT.'/uploads/'.Date("Y")."/".Date("md"); 
if( ! is_dir( $uploaddir ) ) mkdir( $uploaddir, 0777 );

$files      = $_FILES; // полученные файлы
foreach( $files as $file ){
		$file_name = $file['name'];
                $file_name = md5(microtime() . rand(0, 9999)).uniqid().".".getExtension1($file_name);
		if( move_uploaded_file( $file['tmp_name'], "$uploaddir/$file_name" ) ){
                    $done_files = realpath( "$uploaddir/$file_name" );
                    $answer["error"]=false;
                    $answer["errortext"]="";
                    $answer["result"]=$done_files;
		}
}

echo json_encode($answer);

function getExtension1($filename) {
    return end(explode(".", $filename));
};

Одно Но! тут нет контроля, что пользватель выбрал файл без расширения. Хотя с другой стороны, я например это ограничиваю на уровне выбора файла. Например так:

<input id="fileinput" type="file" accept="image/*" capture="capture" >

Вывод в лог файл любых входящих данных скрипта на PHP

Бывает полезно перехватить, что же сыплется на входе в PHP скрипт, если у тебя нет информации об этом. Сделать это можно например так:

<?php
$data="POST:".serialize($_POST)."\n";
file_put_contents('uved.log', $data, FILE_APPEND);

$data="GET:".serialize($_GET)."\n";
file_put_contents('uved.log', $data, FILE_APPEND);


$body = file_get_contents('php://input');

$data="Input:".serialize($body)."\n";
file_put_contents('uved.log', $data, FILE_APPEND);

?>
Увидим что на GET, POST и Input

Как завершить скрипты по таймауту

Задача: ряд скриптов иногда «зависают». Есть два варианта — переделать скрипт, чтобы не «зависал». Не всегда возможно. Второй вариант: отслеживать время работы скрипта, и по какому то предельному значению времени выполнения — убивать. Например так:

#!/usr/local/bin/php
<?php
$timeout=100; // время после которого скрипт считаем зависшим
$res=`ps -ax | grep sos | awk '{print $1,$4}'`;

$resa=explode("\n",$res);

foreach ($resa as $value) {
 if ($value!=""){
  $va=explode(" ",$value);
  $pid=$va[0];
  $timea=explode(":",$va[1]);
    if (isset($timea[1])==true){
      $time=$timea[0];
      echo "PID: $pid, TIME: $time\n";
      if ($time>$timeout){
       `kill $pid`;
      };
    };
  };
};
?>