Recursion in phpagi script of asterisk server - php

I am using this in extension file which execute the my phpagi script:-
exten => s,n,Read(NUMBER,,4)
exten => s,n,agi(a.php,${CALLERID(num)},${NUMBER})
And this in my phpagi script:-
#!/usr/bin/php -q
<?php
require('phpagi.php');
$agi = new AGI();
$NUMBER = $argv[1];
$SSnNUMBER = $argv[2];
------Some Processing----------
$ttresult = $agi->get_data("beep",30000,4);
$ttssn = $ttresult['result'];
$agi->say_digits($ttssn);
$agi->exec("AGI","a.php",$agi->request['agi_callerid'],"$ttssn");
?>
You can see i am using recursion in phpagi script, But this fails every time. There is an error in CLI script:-
AGI Script a.php completed, returning 4

You can't start AGI inside AGI.
Reason: AGI is simple stdin/stdout interface(read doc)
So first AGI connect to asterisk,read info from STDIN,send to STDOUT.
How you expect start script inside it?
You can just use php exec system call, but you need care about initialization of AGI(it already consumend by your script) and about sending stdin/stdout to that process(using pipes or some other way).
In your case you also can use GOTO and set variables for new script.
exten => s,n(repeat),agi(a.php,${CALLERID(num)},${NUMBER})
exten => s,n,GotoIF($[ "${REPEAT}" == "YES" ]?repeat)
Change your script to
#!/usr/bin/php -q
<?php
require('phpagi.php');
$agi = new AGI();
$NUMBER = $argv[1];
$SSnNUMBER = $argv[2];
------Some Processing----------
$ttresult = $agi->get_data("beep",30000,4);
$ttssn = $ttresult['result'];
$agi->say_digits($ttssn);
$agi->set_variable("NUMBER","$ttssn");
$agi->set_variable("REPEAT","YES");
?>

Related

Running Google Chrome headless with PHP exec doesn’t return output till IIS restarted

My environment is Windows Server 2016 and IIS 10. In my PHP script I’m trying to run Google Chrome in a headless mode to get html code of an external web page:
<?php
$chromeApp = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
$command = "\"$chromeApp\" --headless --disable-gpu \
--dump-dom $urladdress > page.html";
exec ($command);
?>
That code works if I run
>C:\php script.php
from the Command line. It also works if I run the actual command:
>"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" \
--headless --disable-gpu --dump-dom https://google.com > page.html
But if I run that script from a browser it creates empty page.html file and hungs till timeout. However if I restart IIS during its execution I get the page.html file filled with the needed data.
What could be a problem here?
this is not an answer, but too much to put in a comment, exec() doesn't really give much feedback,
first don't do this:
$command = "\"$chromeApp\" ";
because different shells can't agree on how stuff should be quoted, so you should use the escapeshellarg() function instead, also don't do this
--dump-dom $urladdress > page.html
because $urladdress may need to be escaped (and if hackers are able to control your $urladdress, then this is actually an arbitrary code execution vulnerability), do this instead:
$command = escapeshellarg($chromeApp)." --headless --disable-gpu \
--dump-dom ".escapeshellarg($urladdress)." > page.html";
(and if your page.html may have names with special characters too, you should run that name through escapeshellarg() as well.)
but replace exec() with proc_open, tell me what you get from running this:
<?php
declare(strict_types=1);
$urladdress="http://google.com";
$chromeApp = _cygwinify_filepath("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe");
$command = escapeshellarg($chromeApp)." --headless --disable-gpu --dump-dom ".escapeshellarg($urladdress);
$descriptorspec = array(
0 => array("pipe", "rb"), // by default stdin is inherited, we don't want that so we create a stdin pipe just so we can fclose() it.
1 => array("pipe", "wb"), // stdout
2 => array("pipe", "wb"), // stderr
);
$proc=proc_open($command,$descriptorspec,$pipes);
if(!$proc){
throw new \RuntimeException("failed to create process! \"{$command}\"");
}
$stdout="";
$stderr="";
$fetch=function()use(&$stdout,&$stderr,&$pipes){
$tmp=stream_get_contents($pipes[1]);
if(is_string($tmp) && strlen($tmp) > 0){
$stdout.=$tmp;
}
$tmp=stream_get_contents($pipes[2]);
if(is_string($tmp) && strlen($tmp) > 0){
$stderr.=$tmp;
}
};
fclose($pipes[0]);
$status=array();
while(($status=proc_get_status($proc))['running']){
$fetch();
}
$fetch();
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($proc);
var_dump($stdout,$stderr,$status);
function _uncygwinify_filepath(string $path) : string
{
static $is_cygwin_cache = null;
if ($is_cygwin_cache === null) {
$is_cygwin_cache = (false !== stripos(PHP_OS, "cygwin"));
}
if ($is_cygwin_cache) {
return trim(shell_exec("cygpath -aw " . escapeshellarg($path)));
} else {
return $path;
}
}
function _cygwinify_filepath(string $path) : string
{
static $is_cygwin_cache = null;
if ($is_cygwin_cache === null) {
$is_cygwin_cache = (false !== stripos(PHP_OS, "cygwin"));
}
if ($is_cygwin_cache) {
return trim(shell_exec("cygpath -a " . escapeshellarg($path)));
//return "/cygdrive/" . strtr($path, array(':' => '', '\\' => '/'));
} else {
return $path;
}
}
edit: i wrote use(&$stdout,$stderr,&$pipes) instead of use(&$stdout,&$stderr,&$pipes), sorry, fixed. re-run it if you just ran it without this fix.
You have 4 processes in play here.
W3WP.exe
PHP.exe
CMD.exe
Chrome.exe
CMD.exe is taking the output of Chrome.exe and piping it to your file. It will do that upon completion of Chrome.exe or may do it partially intermittently. When I run similar code to yours above, my Chrome.exe does not finish. I can see Chrome.exe still running in TaskManager consuming 25% CPU (100% on one of my cores).
I'm guessing restarting IIS somehow forces the flush in progress of the commands. In most of my cases, there was data inside the page.html file prior to doing IISReset, thought not all of it. (Windows Explorer showed 0KBs, but opening the file showed data in the file nonetheless).
As for things to try, try at --no-sandbox as an argument as that may be interfering since the process is running under a non-interactive session.

how exec a cmd command that run log time

when i make server with phantomjs that listen for some port this file open for long time .
i use this code for excute phantomjs with php :
exec('phantomjs server.js');
ans for example phantomjs server file is
if (system.args.length !== 2) {
console.log('Usage: server.js <some port>');
phantom.exit(1);
} else {
port = system.args[1];
var listening = server.listen(port, function (request, response) {
console.log("GOT HTTP REQUEST");
console.log(JSON.stringify(request, null, 4));
// we set the headers here
response.statusCode = 200;
response.headers = {"Cache": "no-cache", "Content-Type": "text/html"};
// this is also possible:
response.setHeader("foo", "bar");
// now we write the body
// note: the headers above will now be sent implictly
response.write("<html><head><title>YES!</title></head>");
// note: writeBody can be called multiple times
response.write("<body><p>pretty cool :)</body></html>");
response.close();
});
because phantomjs server stay long time to answer and exit from it , i cant run other code that below exec line.
is any way to run it from php well .. ?
Problem Solve With:
$WshShell = new COM("WScript.Shell");
$run_cmd = "cmd c:/xampp/php/php.exe c:/xampp/htdocs/Gashash/batch_test.php";
$WshShell = $WshShell->Run($run_cmd, 0, false);
You could run the script in the background. But you lose control over the process.
exec('phantomjs server.js > /dev/null &');
You could also use something like beanstalk / Gearman to separate the two processes.

How can I use exec with cmd in windows? [duplicate]

This question already has answers here:
PHP exec to launch a cmd window with parameters
(1 answer)
How to Gammu sendsms php shell_exec windows 7 and xampp?
(1 answer)
Closed 8 years ago.
How can I run this:
shell_exec('"C:\Program Files\gammu\bin\gammu.exe" --sendsms TEXT 06706177529 -text "halooo"');
With cmd? If i run this in cmd it works very well. So i would like to run it with exec and cmd. I found something like cmd c/ , but how it works?
You will need to use COM.
$shell = new COM("WScript.Shell");
$exec = $shell->Run($cmd, 0, false);
That's a simple example, if you head over to http://php.net/function.exec and take a look at the comments a few people have posted a solution.
Take a look at this comment http://www.php.net/manual/fr/function.exec.php#57538, a nice function is provided to wrap around the above code. I'll paste it here just in case.
<?php
define ('EXEC_TMP_DIR', 'C:\tmp');
function windExec($cmd,$mode=''){
// runs a command line and returns
// the output even for Wind XP SP2
// example: $cmd = "fullpath.exe -arg1 -arg2"
// $outputString = windExec($cmd, "FG");
// OR windExec($cmd);
// (no output since it runs in BG by default)
// for output requires that EXEC_TMP_DIR be defined
// Setup the command to run from "run"
$cmdline = "cmd /C $cmd";
// set-up the output and mode
if ($mode=='FG'){
$outputfile = EXEC_TMP_DIR . "\\" . time() . ".txt";
$cmdline .= " > $outputfile";
$m = true;
}
else $m = false;
// Make a new instance of the COM object
$WshShell = new COM("WScript.Shell");
// Make the command window but dont show it.
$oExec = $WshShell->Run($cmdline, 0, $m);
if ($outputfile){
// Read the tmp file.
$retStr = file_get_contents($outputfile);
// Delete the temp_file.
unlink($outputfile);
}
else $retStr = "";
return $retStr;
}

how to control other scripts by a main script and pass to them parameters when they are running

I have a main.php and test.php.
test.php should be executed by main.php
both scripts must be run infinite.
main.php must checks in periods of time that test.php is running or not and if it isnt running (in case of occuring errors) execute it again.
I must have error logs too.
if main.php recieve 'test stop' it sends 'close' to test.php and test.php must stop (I dont know how send my orders (such as 'test stop') to main.php after that executed?)
I have this samples:
main.php:
<?php
function execute(){
$desc = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('file', 'log.txt', 'a')
);
$cmd = "start /b C:\wamp\bin\php\php5.4.3\php.exe test.php";
$p = proc_open($cmd, $desc, $pipes);
$res[0] = $p;
$res[1] = $pipes;
return $res;
}
$res = execute();
while(1) {
$status = proc_get_status($res[0]);
if (!$status['running']) {
$res = execute();
}
if ( trim(fgets(STDIN)) == 'stop test' ) {
fwrite($res[1][0], 'close');
fclose($res[1][0]);
fclose($res[1][1]);
fclose($res[1][2]);
proc_close($res[0]);
break;
}
}
?>
test.php:
<?php
while (1) {
// ---------
// other commands
// ---------
// ---------
$status = trim(fgets(STDIN));
if ($status == 'close') exit();
}
?>
ok this was summary of my codes but they dont work right.
for example when script arrive to this line $status = trim(fgets(STDIN)); in test.php it waits until an input and if we dont send any input for it, script stops and dont run rest of code but I want script runs in the loop and executes orders until main.php pass an input to him.
I'm working on windows.
I'd say that PHP isn't the best tool for what you're trying to accomplish. Why don't you write a program in C or Visual Basic or something?
But it's solvable in PHP too:
I'd suggest to create your own error-handling function and assign it in test.php via the set_error_handler('my_custom_error_function') function.
In my_custom_error_function() you can log the error and restart test.php
Appending a line to a logfile can be done via file_put_contents('.\error.log', $error_string, FILE_APPEND)
fgets() expects an open file handle. So you may want to check your routines (or provide more code). You may want to look into file_get_contents() too.

How do I pass parameters into a PHP script through a webpage?

I am calling a PHP script whenever a webpage loads. However, there is a parameter that the PHP script needs to run (which I normally pass through the command line when I am testing the script).
How can I pass this argument every time the script is run when the page loads?
Presumably you're passing the arguments in on the command line as follows:
php /path/to/wwwpublic/path/to/script.php arg1 arg2
... and then accessing them in the script thusly:
<?php
// $argv[0] is '/path/to/wwwpublic/path/to/script.php'
$argument1 = $argv[1];
$argument2 = $argv[2];
?>
What you need to be doing when passing arguments through HTTP (accessing the script over the web) is using the query string and access them through the $_GET superglobal:
Go to http://yourdomain.example/path/to/script.php?argument1=arg1&argument2=arg2
... and access:
<?php
$argument1 = $_GET['argument1'];
$argument2 = $_GET['argument2'];
?>
If you want the script to run regardless of where you call it from (command line or from the browser) you'll want something like the following:
as pointed out by Cthulhu in the comments, the most direct way to test which environment you're executing in is to use the PHP_SAPI constant. I've updated the code accordingly:
<?php
if (PHP_SAPI === 'cli') {
$argument1 = $argv[1];
$argument2 = $argv[2];
}
else {
$argument1 = $_GET['argument1'];
$argument2 = $_GET['argument2'];
}
?>
$argv[0]; // the script name
$argv[1]; // the first parameter
$argv[2]; // the second parameter
If you want to all the script to run regardless of where you call it from (command line or from the browser) you'll want something like the following:
<?php
if ($_GET) {
$argument1 = $_GET['argument1'];
$argument2 = $_GET['argument2'];
} else {
$argument1 = $argv[1];
$argument2 = $argv[2];
}
?>
To call from command line chmod 755 /var/www/webroot/index.php and use
/usr/bin/php /var/www/webroot/index.php arg1 arg2
To call from the browser, use
http://www.mydomain.example/index.php?argument1=arg1&argument2=arg2

Categories