Php как узнать pid

Как я могу получить PID PHP-скрипта, запущенного в качестве первой команды в конвейере?

я использую | отправить вывод myscript.php к curl команда. я использую $$ чтобы получить PID, но это возвращает PID curl команда, а не php команда.

Фактически, я буду использовать эту командную строку для всех заданий моего crontab. Вместо того, чтобы получать тысячи писем, я хотел бы отправлять каждую информацию на мой веб-сервис.

Поэтому в myscript.php я вызываю (1 — идентификатор cronjob):

file_get_contents('http://localhost/webservice.php/1/' . getmypid() . '/start/'); . file_get_contents('http://localhost/webservice.php/1/' . getmypid() . '/end/'); 

Я пытаюсь отправить выходные данные myscript.php на веб-сервис, который я создаю.

Поэтому я отправляю команды начала / окончания на мой веб-сервис. Я пропускаю только одно: вывод PHP, если есть предупреждения или какое-то «эхо».

Цель состоит в том, чтобы перенаправить вывод скрипта (который также может быть скриптом bash) в веб-сервис, используя PID команды PHP (которую я использую для идентификации процесса в моем веб-сервисе).

Как я могу получить PID команды PHP? Я пробовал $$, как нашел в Stackoverflow, но, как вы ответили, похоже, что это текущий PID оболочки …

Решение

TL; DR

$$ Переменная является специальной переменной. Он возвращает PID вызывающей оболочки, который может не совпадать с PID текущей оболочки, хранящейся в $ BASHPID. Ни одна из переменных не имеет никакого отношения к PID из процессов в вашем конвейере. Руководство по Bash говорит:

($$) Расширяется до идентификатора процесса оболочки. В подоболочке () она расширяется до идентификатора процесса вызывающей оболочки, а не подоболочки.

Вам нужно реорганизовать ваш PHP-скрипт и ваш конвейер, чтобы сделать что-то другое.

Правильно создавайте уникальные каталоги

Вы не объяснили, что на самом деле делает ваш PHP-скрипт, так что это похоже на проблему X / Y. В общем, вы должны использовать Mktemp или его эквиваленты PHP:

создавать временные или уникальные имена файлов. Поскольку вы, похоже, хотите использовать уникальные каталоги, я приведу это в качестве примера ниже. Тем не менее, может быть чище иметь один каталог, содержащий имена файлов, которые гарантированно будут уникальными. Ваш пробег может отличаться.

Вместо того, чтобы пытаться использовать PID, вы должны использовать Mktemp Утилита для создания уникальных каталогов или имен файлов без условий гонки. Если вы делаете это в Bash, вы можете экспортировать переменную в среду, а затем использовать ту же директорию внутри вашего PHP-скрипта. Например:

#!/usr/bin/env bash # Create a unique temp directory safely. export DIR=$(mktemp -d) # Create your output directory for whatever reason. mkdir "$DIR/output" # Ensure PHP uses $_ENV["DIR"] to do whatever it's doing. php myscript.php | curl -X POST --data-binary @- "file://$DIR/output/" # Clean up the temp directory at some point. echo "I did something with '$DIR' so clean it up later." > /dev/stderr 

Просто используйте уникальные файлы с префиксами

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

# Create files like "/tmp/myscript.D6147vts"export TEMPFILE=$(mktemp -t myscript) 

Затем, как и раньше, используйте $_ENV[«TEMPFILE»] в вашем скрипте PHP. Преимущество этого подхода заключается в том, что ваши имена файлов гарантированно будут уникальными, но все они в одном месте и имеют общий префикс. Это может сделать очистку или поиск нужного файла намного проще в дальнейшем.

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

Другие решения

Пытаться
ps aux | grep «идентификатор процесса» и pid, если второй столбец. Разобрать его с помощью pnp_exec; то есть, сохранить его в массиве и извлечь номер PID.

Источник

proc_get_status

proc_get_status() fetches data about a process opened using proc_open() .

Parameters

The proc_open() resource that will be evaluated.

Return Values

An array of collected information. The returned array contains the following elements:

element type description
command string The command string that was passed to proc_open() .
pid int process id
running bool true if the process is still running, false if it has terminated.
signaled bool true if the child process has been terminated by an uncaught signal. Always set to false on Windows.
stopped bool true if the child process has been stopped by a signal. Always set to false on Windows.
exitcode int The exit code returned by the process (which is only meaningful if running is false ). Only first call of this function return real value, next calls return -1 .
termsig int The number of the signal that caused the child process to terminate its execution (only meaningful if signaled is true ).
stopsig int The number of the signal that caused the child process to stop its execution (only meaningful if stopped is true ).

See Also

User Contributed Notes 10 notes

On Unix/Linux, if you change the command line you pass to proc_open() just slightly then proc_get_status() will give you the actual process-id (pid) of your child.

Suppose you wish to run the external command /usr/bin/compress to create a BSD foo.Z file. Rather than proc_open(«/usr/bin/compress /tmp/foo». ) you may invoke proc_open(«exec /usr/bin/compress /tmp/foo». ) and then proc_get_status()[‘pid’] will be the actual pid of /usr/bin/compress.

Why? Because the way proc_open() actually works on Unix/Linux is by starting «/bin/sh -c usercmd userargs. «, e.g., «/bin/sh -c /usr/bin/compress /tmp/foo».[Note 1] That means normally your command is the child of the shell, so the pid you retrieve with proc_get_status() is the pid of the shell (PHP’s child), and you have to fumble around trying to find the pid of your command (PHP’s grandchild). But if you put «exec» in front of your command, you tell the shell to *replace itself* with your command without starting another process (technically, to exec your command without forking first). That means your command will inherit the pid of the shell, which is the pid that proc_get_status() returns.

So if you would like the actual pid of the process running your command, just prepend «exec » to your proc_open() command argument then retrieve the pid using proc_get_status().

This also makes proc_terminate() and proc_close() work more like you might prefer, since they will affect the actual process running your command (which will be a child process rather than a grandchild process).

[Note 1] My guess is that the PHP developers want the shell to expand wildcards in path/filenames.

For clarification, the «exitcode» is only valid the FIRST TIME IT IS CALLED after the process exits.

If you have a method that polls a spawned process for its status, you *MUST* have that same method capture the exitcode: if the method is called a second time (after realizing the pid is dead) and it hasn’t cached that exitcode, it will receive the -1 mentioned.

It is worth noting that proc_get_status will continue to indicate the process that you spawned is running (because it is!) until that process has been able to write everything it wants to write to the STDOUT and STDERR streams.

PHP seems to use a buffer for this and so the spawned process can can get it’s write calls to return immediately.

However, once this buffer is full the write call will block until you read out some of the information from the stream/pipe.

This can manifest itself in many ways but generally the called process will still be running, but just not doing anything as it is blocking on being able to write more to STDERR or STDOUT — whichever stream buffer is full.

To work around this you should include in your loop of checking proc_get_status’ running element a «stream_get_contents» on the relevant pipes.

I generally use stream_set_blocking($pipies[2], 0) kind of calls to make sure that the stream_get_contents call will not block if there is no data in the stream.

This one had me stumped for a while, so hopefully it helps someone!

The following function takes an array of shell commands and executes them. It is able to execute up to $nb_max_process at the same time. As soon as one process is terminated, another one is executed. Quite useful if you want to batch process commands on a multi-processor or multi-core environment.

The example below tries to convert to PNG a list of SVG files submitted on the command line (using Inkscape).

(it’s quick and dirty but works very well for me)

#!/usr/bin/php
function pool_execute ( $commandes , $nb_max_process ) $pool =array();
for( $i = 0 ; $i < $nb_max_process ; $i ++) $pool [ $i ]= FALSE ;
>

while( count ( $commandes )> 0 ) $commande = array_shift ( $commandes );

$commande_lancee = FALSE ;
while( $commande_lancee == FALSE ) usleep ( 50000 );

for( $i = 0 ; $i < $nb_max_process and $commande_lancee == FALSE ; $i ++) if( $pool [ $i ]=== FALSE ) $pool [ $i ]= proc_open ( $commande ,array(), $foo );
$commande_lancee = TRUE ;
> else $etat = proc_get_status ( $pool [ $i ]);
if( $etat [ ‘running’ ]== FALSE ) proc_close ( $pool [ $i ]);
$pool [ $i ]= proc_open ( $commande ,array(), $foo );
$commande_lancee = TRUE ;
>
>
>
>
>
>

$fichiers = $argv ;
array_shift ( $fichiers );
$commandes =array();
foreach( $fichiers as $fichier ) $entree = $fichier ;
$sortie = basename ( $fichier , ‘.svg’ ). «.png» ;
$commandes []= ‘inkscape —file=’ . escapeshellarg ( $entree ). ‘ —export-area-canvas —export-png=’ . escapeshellarg ( $sortie );
>

pool_execute ( $commandes , 4 );

You can NOT rely on pid+1.
You could prefix exec to the command string, this will replace the /bin/sh script with the real thing you want to exec (use only if you don’t do ‘scary things’ like pipes, output redirection, multiple commands, however if you know how they work, go ahead).
If you prefix exec, the /bin/sh process will only start your process, and the PID will be the same.

If launching a GNU screen with proc_open, subsequents proc_get_status always return (wrongly) running = false

$descriptorspec = array(
0 => array(«pipe», «r»), // stdin
1 => array(«pipe», «w»), // stdout
2 => array(«pipe», «w») // stderr
);
$p = proc_open(‘screen . ‘, $descriptorspec, $pipes);
var_dump(proc_get_status($p)[‘running’]); // false (wrong)

Alternatively, if you’re calling a subsequent php script using proc_open, you can have that process echo its own actual PID in the output.
Also, if you go through the /proc filesystem on linux, you can read through /proc/12345 where 12345 is the pid returned by proc_get_status (the pid of the /bin/sh instance) and it will list its child processes within.

Further to my previous note, I’ve found out the PID returned is the PID of the shell (/bin/sh) that then runs the actual command requested.

I’ve raised this as bug #41003.

To the poster above, same here on FreeBSD 6.1, PHP 5.2.1.

To get the correct PID to use for posix_kill I have to add 1 to the PID returned from proc_get_status.

I have had lots of problems in the past bit trying to kill external commands run by proc_open.

Others have suggested using ps to find the children of the pid returned by proc_get_status, but on my system this doesn’t work. I’m using php-5.2.5 and apache-2.0.59 on linux kernel 2.6.21, and the processes I start with proc_open end up being owned by init (pid 1), not by the pid returned by proc_get_status.

I did notice, however, that the pid’s of the processes were always above and very close to the proc_get_status pid. Using that information, I wrote a little function that takes the name of a command, the starting pid at which to search (which would be the proc_get_status pid), and optionally a search limit as arguments. It will use ps to list processes owned by apache (you may have to change this user name for your system), and search for the command specified. The limit tells how far above the starting pid to search. This will help if the command may have already exited, and you don’t want to kill a process from a different session than the one you’re working with.

function findCommandPID ( $command , $startpid , $limit = 3 )
<
$ps = ` ps -u apache —sort=pid -o comm= -o pid= `;
$ps_lines = explode ( «\n» , $ps );

foreach( $ps_lines as $line )
<
if( preg_match ( $pattern , $line , $matches ))
<
//this limits us to finding the command within $limit pid’s of the parent;
//eg, if ppid = 245, limit = 3, we won’t search past 248
if( $matches [ 3 ] > $startpid + $limit )
break;

//try to match a ps line where the command matches our search
//at a higher pid than our parent
if( $matches [ 1 ] == $command && $matches [ 3 ] > $startpid )
return $matches [ 3 ];
>
>

Источник

Читайте также:  Advanced topic in python
Оцените статью