rename() gives undocumented return value NULL - php

After an update from PHP7.0 to PHP7.2 some code stopped working and I don't understand why:
$res = rename($tmpfile, $output_file);
if ($res !== true) {
throw new Exception("Unable to rename temporary file");
}
In php7.2 the exception is triggered, although the rename was successfully done, the file is perfectly readable and nothing has gone wrong. Still I get the exception, because the return value is NULL. I inserted some debugging code:
$res = rename($tmpfile, $output_file);
log('Debug: $res ' . $res);
log('Debug: $res true? ' . $res === true);
log('Debug: $res type ' . gettype($res));
if ($res !== true) {
throw new Exception("Unable to rename temporary file");
}
This gives the following output:
2018-08-03 10:37:39 Debug: $res
2018-08-03 10:37:39
2018-08-03 10:37:39 Debug: $res type NULL
2018-08-03 10:37:39 CURL_DOWNLOAD Exception: Unable to rename temporary file
#0 /var/www/formr.org/application/Library/Functions.php(1470): CURL::DownloadUrl('http://docs.goo...', '/var/www/formr....', NULL, 'GET', Array, Array)
As you can see, there is no output, and the type is NULL. That is an undocumented behavior. According to the php documentation the return value must be nothing but true or false.
I couldn't find any documentation that the behavior of this function was changed. Does someone understand this?
Thanks for help!
Edit: var_dump output
$res = rename($tmpfile, $output_file);
ob_start();
var_dump($res);
$contents = ob_get_contents();
ob_end_clean();
log('Debug $res: ' . $contents);
Gives:
2018-08-03 12:37:40 Debug $res: NULL
Testing rename()-function in terminal:
user$ sudo su www-data -s /bin/bash
www-data$ php -a
Interactive mode enabled
php > $old='/var/www/path/changed/filename.xlsx';
php > $new='/var/www/path/changed/newfilename.xlsx';
php > $res = rename($old, $new);
php > var_dump($res);
bool(true)
(I changed the filenname and path for privacy reasons, but I tested it on the original file.)
PHP version:
$ php --version
PHP 7.2.7-0ubuntu0.18.04.2 (cli) (built: Jul 4 2018 16:55:24) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.7-0ubuntu0.18.04.2, Copyright (c) 1999-2018, by Zend Technologies
The PHP version installed is the one that comes shipped with Ubuntu 18.04. I didn't recompile it myself.
The program has its own rename functions, at two times, as I just noticed. But they are not about renaming files, they rename something in the database.
They both have just one parameter. PHP does not support overloading or differentiation by number of arguments, so might there be some interference? So far this hasn't been an issue. And as the file is actually renamed, I don't believe that the wrong function is called.

Solved by last comment of Apokryfos: Properly calling the rename-function with namespace \rename($old,$new) gives me bool(true) as return value.

Related

Can't execute a php script without using "php" command before

I need to use a php script without "php" command.
For example:
$ ./test.php
Permissions are sets to 755.
This is the script
#!/usr/bin/php -q
<?php
echo "hello world";
?>
/usr/bin/php -v (so path exists)
returns
PHP 7.0.15-1+deb.sury.org~xenial+1 (cli) (built: Jan 20 2017 08:53:13) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.0.15-1+deb.sury.org~xenial+1, Copyright (c) 1999-2017, by Zend Technologies
This is the error I'll get everytime:
Exception: Zend Extension ./test.php does not exist
Also calling script with fullpath I'll get same error.
Calling this it works properly
$ php ./test.php
Any idea?
NOTE: The author found the solution and put it up in the comments but never posted an actual answer, so this answer is just clarifying what the author already said above so as to make the answer more obvious.
I was also getting the Exception: Zend Extension does not exist when I was trying to pipe an email via cpanel forwarder into a php script.
I opened the file in my editor (Komodo Edit on Windows) and went to EDIT > CURRENT FILE PREFERENCES and noticed that LINE ENCODINGS was set to DOS/Windows (\r\n)
I changed the LINE ENCODING to UNIX (\n) and saved it and re-uploded it and the error went away and all is good now.
Obviously the steps will vary depending on what editor you use, but the solution is to make sure your Line Encodings are UNIX and not DOS/Windows.
Just run dos2unix on the file
# ./database.php
Exception: Zend Extension ./database.php does not exist
# apt install dos2unix
# dos2unix database.php
dos2unix: converting file database.php to Unix format...
# ./database.php
Yeah!!! It work's!!!!

PHPUnit on pre-commit Git Hook seems to use different PHP version

I'm trying to set up a pre-commit git hook that will run and validate our unit tests. We are using PHPUnit in the Symfony 2 platform.
For some reason it seems that when I run the unit tests via the git hook that it is using a different version of PHP.
When I check my php version I get:
php -v
PHP 5.4.14 (cli) (built: May 8 2013 10:23:18)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
with Xdebug v2.2.1, Copyright (c) 2002-2012, by Derick Rethans
Here is my git hook:
#!/usr/bin/php
<?php
// Hook configuration
$project = 'My Project';
// Tell the commiter what the hook is doing
echo PHP_EOL;
echo '>> Starting unit tests'.PHP_EOL;
// Execute project unit tests
exec('bin/phpunit -c app/', $output, $returnCode);
// if the build failed, output a summary and fail
if ($returnCode !== 0)
{
// find the line with the summary; this might not be the last
while (($minimalTestSummary = array_pop($output)) !== null)
{
if (strpos($minimalTestSummary, 'Tests:') !== false)
{
break;
}
}
// output the status and abort the commit
echo '>> Test suite for '.$project.' failed:'.PHP_EOL;
echo $minimalTestSummary;
echo chr(27).'[0m'.PHP_EOL; // disable colors and add a line break
echo PHP_EOL;
exit(1);
}
echo '>> All tests for '.$project.' passed.'.PHP_EOL;
echo PHP_EOL;
exit(0);
When I run the unit tests manually ("bin/phpunit -c app/" from my project directory) the tests execute with out error. When I run the tests via the git hook I get a PHP Parse Error. I've determined that the parse error stems from the use of array bracket notation (['key'=>'value']) that was added in PHP 5.4
When I echo php -v in the git hook I get the following output
Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies
Since the Zend Engine is different (2.4.0 when run manually and 2.3.0 when run via the git hook) I'm assuming that there is a PHP version mismatch happening.
Does anyone have any clues as to why this is happening?
Thanks!
the git/phpunit executable most likely sees a different PATH environment variable than your shell (bash/zsh/...) executable.
If a program looks for i.e. php - the first match from your PATH variable will be used.
Probably you're adding a folder containing a different PHP executable to the PATH variable in one of your shell startup files.
Possible files include:
/etc/profile
/etc/zshenv
/etc/bashrc
~/.profile
~/.bashrc
~/.zshrc
...

Run php from the command line linux

I am trying to run a php file from the command line (I want to eventually put it in a cron job) on an Ubuntu server. Nothing seems to happen when I enter the command. I've tried:
php -f foo.php
and
php foo.php
I have cli installed and the foo.php is set to executable.
The script should be testing whether it still has access to a database and emailing the results. It works fine when reached from the web browser.
Any idea on what I'm doing wrong?
EDIT:
Output from php -v
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
with Suhosin v0.9.33, Copyright (c) 2007-2012, by SektionEins GmbH
EDIT:
The script:
<?php
require_once __DIR__.'/../Classes/DBConnection.php';
require_once __DIR__.'/../Classes/Mail.php';
$dbSlave = DBConnection::getSlaveDB();
$db = DBConnection::getDB();
$unique = uniqid();
try{
$query = 'INSERT INTO tblzzTestSlave (token) VALUES (:token)';
$statement = $db->prepare($query);
$statement->bindValue(':token', $unique);
$statement->execute();
$slaveQuery = "SELECT id FROM tblzzTestSlave WHERE token=:token";
$slave = $dbSlave->prepare($slaveQuery);
$slave->bindValue(':token', $unique);
$slave->execute();
$result = $slave->fetch();
}catch (Exception $e){
$result = null;
}
if(!$result){
Mail::smtpMailer('email', 'email', 'from','Slave Not Working', 'The Slave has stopped working');
}
You may check if PHP uses the correct configuration file.
That may be different on the command line and running in a server environment.
Type this to see which config it uses:
php --ini
I was stupid. This line:
require_once __DIR__.'/../Classes/Mail.php';
Mail required another file which attempted to check the session cookie. Which of course I didn't have because I was running it from the command line. This is why it worked in the browser (I was signed in). When there is not session cookie it would attempt to redirect me to the sign in page which obviously doesn't work from the CL.

Segmentation Fault running Gearman PHP from the Command Line

I'm using Ubuntu Natty with PHP 5.3.5 and PECL Gearman 0.8.0. Here's the version info:
PHP 5.3.5-1ubuntu7.3 with Suhosin-Patch (cli) (built: Oct 13 2011 22:20:48)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
with the ionCube PHP Loader v4.0.10, Copyright (c) 2002-2011, by ionCube Ltd., and
with Zend Guard Loader v3.3, Copyright (c) 1998-2010, by Zend Technologies
with Suhosin v0.9.32.1, Copyright (c) 2007-2010, by SektionEins GmbH
I'm getting a segmentation fault when trying to run a Gearman Client via the command line (I already have my worker running).
Here's what I get on the command line:
root#Local:~/sandbox# php php_gearman_client.php
Sending job
Segmentation fault
Here is my worker code:
<?php
echo "Starting\n";
# Create our worker object.
$gmworker= new GearmanWorker();
# Add default server (localhost).
$gmworker->addServer();
# Register function "reverse" with the server. Change the worker function to
# "reverse_fn_fast" for a faster worker with no output.
$gmworker->addFunction("reverse", "reverse_fn");
print "Waiting for job...\n";
while($gmworker->work())
{
if ($gmworker->returnCode() != GEARMAN_SUCCESS)
{
echo "return_code: " . $gmworker->returnCode() . "\n";
break;
}
}
function reverse_fn($job)
{
echo "Received job: " . $job->handle() . "\n";
$workload = $job->workload();
$workload_size = $job->workloadSize();
echo "Workload: $workload ($workload_size)\n";
# This status loop is not needed, just showing how it works
for ($x= 0; $x < $workload_size; $x++)
{
echo "Sending status: " . ($x + 1) . "/$workload_size complete\n";
$job->sendStatus($x, $workload_size);
sleep(1);
}
$result= strrev($workload);
echo "Result: $result\n";
# Return what we want to send back to the client.
return $result;
}
# A much simpler and less verbose version of the above function would be:
function reverse_fn_fast($job)
{
return strrev($job->workload());
}
?>
And here is my client code:
<?php
# Create our client object.
$gmclient= new GearmanClient();
# Add default server (localhost).
$gmclient->addServer();
echo "Sending job\n";
# Send reverse job
do
{
$result = $gmclient->do("reverse", "Hello!");
# Check for various return packets and errors.
switch($gmclient->returnCode())
{
case GEARMAN_WORK_DATA:
echo "Data: $result\n";
break;
case GEARMAN_WORK_STATUS:
list($numerator, $denominator)= $gmclient->doStatus();
echo "Status: $numerator/$denominator complete\n";
break;
case GEARMAN_WORK_FAIL:
echo "Failed\n";
exit;
case GEARMAN_SUCCESS:
break;
default:
echo "RET: " . $gmclient->returnCode() . "\n";
exit;
}
}
while($gmclient->returnCode() != GEARMAN_SUCCESS);
?>
EDIT
It appears the segmentation fault was being caused by Imagick. So I did the following to deal with the issue.
Remove imagick dpkg --purge --force-all php5-imagick. I had installed this when I was setting up PHP
Restart PHP (This could vary depending on how you installed php)
Restart Gearman Job Server /etc/init.d/gearman-job-server stop && /etc/init.d/gearman-job-server
Everything seems to be working ok now.
since it is segmentation fault that means something is wrong with your installation. Run dmesg to see more details there may be problem with some php extension that could be disabled.
I just also had this problem.
This is the soution I took (to fully resolving it), and steps to observing the error.
Step 1.
Running the Gearman Worker resulted in a:
Segmentation fault
Step 2.
Run dmesg from shell, I observed that this was showing up.
[2423402.716386] php[21232]: segfault at 30 ip b66d0321 sp bfc704c0
error 6 in libuuid.so.1.3.0[b66cf000+3000]
Step 3.
Googled for libuuid.so and it became apparent that Imagick uses uuid_create() for Image UUIDs.
http://usrportage.de/archives/922-PHP-segfaulting-with-pecluuid-and-peclimagick.html
Step 4. (The solution)
I ensured that Imagick extension gets initialized last out of all of my PHP extensions.
So previously I had in the first line of my
/etc/php5/conf.d/extensions.ini file imagick.so
What I did instead was created a file called imagick.ini and the contents of that were
imagick.so
Because the extensions are loaded in alphabetical order (and if you are running your Worker through command line), loading imagick last ensures that all the dependant extensions are loaded first. In this case libuuid.

Execute "less" from command-line PHP w/ Scrolling

I want to execute less and similar programs from the command-line in PHP.
I have tried the usual suspects (exec, shell_exec, passthru, etc), and while many of them can dump the file to the screen, the process is terminated before I can make use of it. If I wanted cat, I'd use it.
How do I execute a program in this fashion?
You could use proc_open to feed input to and get output back from a process via pipes. However, it doesn't seem like less allows for user interaction via pipes as it basically degrades to a cat command. Here's my first (failed) approach:
<?php
$dspec = array(
0 = array('pipe', 'r'), // pipe to child process's stdin
1 = array('pipe', 'w'), // pipe from child process's stdout
2 = array('file', 'error_log', 'a'), // stderr dumped to file
);
// run the external command
$proc = proc_open('less name_of_file_here', $dspec, $pipes, null, null);
if (is_resource($proc)) {
while (($cmd = readline('')) != 'q') {
// if the external command expects input, it will get it from us here
fwrite($pipes[0], $cmd);
fflush($pipes[0]);
// we can get the response from the external command here
echo fread($pipes[1], 1024);
}
fclose($pipes[0]);
fclose($pipes[1]);
echo proc_close($proc);
I guess for some commands this approach might actually work - and there are some examples in the php manpage for proc_open that might be helpful to look over - but for less, you get the whole file back and no possibility for interaction, maybe for reasons mentioned by Viper_Sb's answer.
...But it seems easy enough to simulate less if that's all you need. For example, you could read the output of the command into an array of lines and feed it in bite-sized chunks:
<?php
$pid = popen('cat name_of_file_here', 'r');
$buf = array();
while ($s = fgets($pid, 1024))
$buf[] = $s;
pclose($pid);
for ($i = 0; $i < count($buf)/25 && readline('more') != 'q'; $i++) {
for ($j = 0; $j < 25; $j++) {
echo array_shift($buf);
}
}
I don't believe this is possible. PHP is not a VM/shell environment, the commands it has to access other programs all return control to it, and normally there is no interaction while PHP is running.
One last thing, try with the backtick operators, if that doesn't work then I'm pretty sure you can't do this without writing up something yourself that will sleep and allow user input etc... by default no
`nano file.txt`
Adding exec('stty cbreak'); to the PHP script also fixes the issue.
I put the following in a file defined by the auto_prepend_file setting in php.ini
So, I would do something like edit php.ini to the following:
auto_prepend_file = /path/to/prepend.php
Then in, /path/to/prepend.php, I would add the following line:
if (php_sapi_name() == 'cli') exec('stty cbreak');
I'm not exactly sure of the cause. I've read bug reports for PHP. I'm not sure about versions though. I noticed the problem with the following setup:
$ php -v
PHP 5.3.3 (cli) (built: Jul 12 2013 20:35:47)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
However, the following did not show the issue:
# php -v
PHP 5.3.26 (cli) (built: Oct 21 2013 16:50:03)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies
with the ionCube PHP Loader v4.4.1, Copyright (c) 2002-2013, by ionCube Ltd.
It is worth noting that the version without the issue was using cPanel and the other was using the default CentOS 6 install via yum.

Categories