Param to array_map() not a string, PHPCS did not find it - php

I did use something like
$foo = array_map(preg_quote, $some_list);
in my code. This worked fine with PHP 7.4, but did break with PHP 8.1.
The problem: I had to put preg_quote in quotes ;-), so
$foo = array_map('preg_quote', $some_list);
fixes my problem.
But: I did use phpcs with
--standard=PHPCompatibility --runtime-set testVersion 8.1
for all of my files, but I did not get any warning.
I am a bit nervous since I believed to find all incompabibility stuff with phpcs (or at least most).
Does anyone have an idea how to better find such incompatibilities with some "automatic" scan?

Related

PHP Static analysis to detect breaking changes in advance of upgrade

We have a large codebase and it's currently running in production on PHP 7.4. Now we're getting ready to upgrade to PHP 8.1 and so we've been asked to make sure the code is going to work when we upgrade.
We have phpcs of course, and this will detect things that have been completely removed by PHP 8.1 (or PHP8.0) to make sure that the code runs without fatal errors, but there are a bunch of things listed in the migration docs from php7.4 to php8.0 where behaviour will change and I don't see any warnings that if I upgrade to 8.0 then my code will behave differently. Or said another way, I'd like to be pointed to the exact places that I need to modify my code if I want the behaviour not to change after the upgrade.
To illustrate, here's a file test.php:
<?php
if(0 == "foo") {
echo "this was true in php 7.4, you must be running 7.4 or lower\n";
} else {
echo "this is false in php 8.0, you must be running 8.0 or higher\n";
}
Because of a change between PHP 7.4 and PHP 8.0 the behaviour of this code will differ depending on which version of php is running it, but I haven't found how phpcs can be made to warn me about this while I'm still on 7.4 and preparing to go to 8.0. I've tried:
composer global require squizlabs/php_codesniffer:^3 phpcompatibility/php-compatibility:^9
$(composer config -g home)/vendor/bin/phpcs \
--standard=$(composer config -g home)/vendor/phpcompatibility/php-compatibility \
--runtime-set testVersion 8.1 test.php
But this doesn't detect the if(0 == "foo") { which might break everything post upgrade...
There seem to be quite a few tools that check for backward compatibility but I guess I'm looking for checking forward compatibility.
Is this doable with phpcs? Or is there another static analysis tool that will help me prepare for an upgrade by catching these breaking changes? If not, what other ways of preparing for an upgrade do you recommend, considering a very large codebase?

Compile C++ file Using PHP

I am using PHP on Windows machin. I also use Dev C++. I can perfectly compile .cpp file on CMD using this command:
g++ hello.cpp -O3 -o hello.exe
Now what I am trying to do is running the same command using php system() function, so it looks like this:
system("g++ c:\wamp\www\grader\hello.cpp -O3 -o C:\wamp\www\grader\hello.exe");
but it doesn't compile. I am lost, please tell me what am I missing?
I also looked up at this question and thats exactly what I need, but I couldnt find a usefull solution for my case there:
Php script to compile c++ file and run the executable file with input file
Use the PHP exec command.
echo exec('g++ hello.cpp -O3 -o hello.exe');
should work.
There's a whole family of different exec & system commands in PHP, see here:
http://www.php.net/manual/en/ref.exec.php
If you want the output into a variable, then use :
$variable = exec('g++ hello.cpp -O3 -o hello.exe');
If that doesn't work, then make sure that g++ is available in your path, and that your logged in with sufficient enough privliges to allow it to execute.
You may find also that it's failing beacuse PHP is essentially being executed by your web server (Unless your also running PHP from the cmd prompt) , and the web server user ID may not have write access to the folder where G++ is trying to create the output file.
Temporarily granting write access to 'Everybody' on the output folder will verify if that is the case.
Two things:
You are using double quotes and are not escaping the \ inside the path.
You are not using a full path to g++.
The first one is important as \ followed by something has a special meaning in such a string (you might know \n as new line), the second one is relevant since the PHP environment might have a different search path.
A solution might be
system("c:\\path\\to\\g++ c:\\wamp\\www\\grader\\hello.cpp -O3 -o C:\\wamp\\www\\grader\\hello.exe");
Alternatively you can use single quotes, intead of double quotes, they use diffeent,less strict escaping rules
system('c:\path\to\g++ c:\wamp\www\grader\hello.cpp -O3 -o C:\wamp\www\grader\hello.exe');
or use / instead of \, which is supported by windows, too.
system("c:/path/to/g++ c:/wamp/www/grader/hello.cpp -O3 -o C:/wamp/www/grader/hello.exe");
What you do is your choice, while many might consider the first one as ugly, and the last one as bad style on Windows ;-)
Thanks to everyone. I tried to run the codes given in above posts and it worked like a charm.
I ran the following code using my browser
$var = exec("g++ C:/wamp/www/cpp/hello.cpp -O3 -o C:/wamp/www/cpp/hello.exe");
echo $var;
The exe file is created. I am able to see the result when i run the exe file but the problem is when i run the above code in the browser, the result is not displayed on the webpage. I gave full access permission to all users but still give does not show the result on the webpage.
I really need help on this since i am doing a project on simulated annealing where i want to get the result from compiled c++ program and display it in the webpage with some jquery highcharts.
Thanks again to all, it has helped me alot and i have learnt alot as well.

Is there a PHP syntax checker for Notepad++?

Is there a PHP syntax checker plugin for Notepad++?
Please don't answer "Use another editor instead"
Try NppExec plugin for Notepad++. Using it create a command to be something like this:
cmd.exe /K c:\your\path\to\php.exe -l "YOUR_FULL_FILE_NAME"
Instead of YOUR_FULL_FILE_NAME you should use appropriate Notepadd++ macro -- I think it is $(FULL_CURRENT_PATH) but double check with NppExec manual (installs together with plugin).
P.S.
But any IDE will be better for sure (I'm using PhpStorm). If IDE is too heavy for your PC then look for php-oriented editors, like Blumentals RapidPHP etc (it's lighter than full IDE but may have all really important features).
As LazyOne said above, you can use NppExec which you can install using the plugin manager (Plugins>Plugin Manager>Show Plugin Manager) You'll also need to have PHP installed. Lastly, the command I use to do PHP syntax checking with NppExec is
"C:\Program Files (x86)\PHP\php.exe" -l $(FULL_CURRENT_PATH)
I recommend you find a true IDE (not a glorified text editor). I've used Notepad++ for years but it can't do much beyond syntax highlighting.
I personally use PHPStorm (but it's not free, it is very good though :D ). You could also use NetBeans or Eclipse.
Adding to #LazyOne's answer:
I don't like NetBeans, it's too strict, has a tough time finding includes, and it's slow. I dig N++ for its speed and simplicity. I have php installed on my PC really just to run validation. If you're using N++ (or any other text editor) you can use the following Powershell script to batch check all of the files you've downloaded and are working on. Just fire up Powershell ISE, enter the correct path to check and PHP.exe path for your environment and the results get output to the ISE console.
cls
$pathToCheck = "C:\Users\BigDaddy\AppData\Local\Temp\fz3temp-1"
$phpExePath = "C:\PHP\php.exe"
Get-ChildItem $pathToCheck -Filter "*.php" | foreach {
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $phpExePath
$pinfo.Arguments = "-l", $_.FullName
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$output = $p.StandardOutput.ReadToEnd()
$output += $p.StandardError.ReadToEnd()
$output
}
I hope someone else finds this as useful as I have.
Cheers!
I use Komodo Edit 7 (free version) which has a built-in php syntax checker. I dunno how robust it is, but it works fine for me. I’m not a pro web designer, but I like it better then Eclipse and Bluefish. Komodo is smaller than Eclipse and more stable than Bluefish (in my Win XP environment).
PHP can syntax check your file using the -l lint option. Install PHP (if you haven't already) on your computer and use the Run function in Notepad++ and run a command like this:
cmd.exe /S /K ""C:\Program (portable)\php-8.0.12-Win32-vs16-x64\php.exe" -l "$(FULL_CURRENT_PATH)""
Change the path to your install location. After running it via Run you are able to save it, give it a name and assign a custom keyboard shortcut.
Breakdown of the command:
cmd.exe /S /K open a new Command shell which will stay open after executing, /S for being able to wrap the whole command to execute in cmd.exe in quotes
"C:\Program (portable)\php-8.0.12-Win32-vs16-x64\php.exe" launch php.exe
-l option of php.exe to use their lint service rather than executing
"$(FULL_CURRENT_PATH)" Notepad++ specific which gives the full path to the current open document

Find out where a function comes from?

From time to time, I'm handed bloated, undocumented, buggy PHP code to fix. I have several tools I use to fix such code as quickly as possible.
One thing I'm not sure how to do that occasionally causes me grief is finding where a function is located (in which file it is defined). Note that I don't want to know where a function is called from.
For example I'd like to be able to do this:
//file1.php
function foo(){
echo 'bar';
}
.
//file2.php
where_is_function('foo');//error
include('file1.php');
echo where_is_function('foo');//outputs'file1.php'
Get yourself a good IDE such as netbeans or eclipse. They have functionality to find function declarations, and also find the usages of those functions (under refactoring).
Personally I use netbeans. I simply have to ctrl-click on a function name & netbeans will find where the function is defined, and automatically open the file for me.
grep or grep-like tools. I prefer ack, which makes the output much easier to read and ignores version-control files by default. I highly prefer these tools to constraining myself to code in a bloated, click-hogging IDE. Finding things this way has always worked better than things like Eclipse for me anyway.
To use grep, you would cd to the base directory and then recursively grep the contents of the directory for the function name, possibly including the keywords to define a function. Like this:
cd project/
grep -Rn "def wallace(" .
Ack is like:
cd project/
ack "def wallace("
Try this:
function getFunctionLocation($fname) {
$includeFilesString = implode(" ", get_included_files());
return system("grep 'function $fname' $includeFilesString -l");
}
But if it's only for development purposes, which it should be, then just run
grep -r "function functionName" *
from the base directory

PHP #exec is failing silently

This is driving me crazy. I'm trying to execute a command line statement on a windows box for my PHP web app. It's running on windows XP, IIS5.1. The web app is running fine, but I cannot get #exec() to work with a specific contactenated variable. My command construction looks like this:
$cmd = ($config->svn." cat ".$this->repConfig->svnParams().quote($path).' -r '.$rev.' > '.quote($filename));
This command does not work as is above, when it generates the following string:
svn --non-interactive --config-dir /tmp cat "file:///c:/temp/test/acccount/dbo_sproctest.sql" -r 1 > "C:\Inetpub\sites\websvn\temp\wsv5B45.tmp"
If I copy/paste this to my own command line, it works fine.
If I hard code that very same path instead of adding it with the variable, it works! I've tried with and without quotes around the file name. I've tried with and without quotes around the entire command. I've tried other directories. I've tried passing an output paramter to exec(), and it comes back empty (Array () ). I've tried redirecting the output of the error stream of the command to a file, and that error output file never gets created.
The only thing I can possibly concieve of is that exec() is failing silently. What on earth am I doing wrong here? If I hard code the file path, using the same dir structure and filename, it works fine. If I don't, it doesn't.
Maybe the slashes () in the file path aren't being escaped properly, but when I do it manually with single quotes they are not considered escape sequences??
UPDATE:
I took the # off of exec, and still not seeing any errors.
I gave the full path to SVN, still no luck. It should be noted that the command worked fine before with the non-full path SVN so long as I manually specify the file destination for cat.
Update 2: RE: Kieth
I'm calling exec by trying both:
exec($cmd);
or
exec($cmd, $out);
My php.ini already had safe_mode = 0.
I added error_reporting(E_ALL); and didn't see anything new
If I echo (or print_r) my exec call, I am not actually seing anything
If I echo (or print_r) my exec call when included an output var, I get an empty arr
Update 3
I tried both escapeshellcmd and escapeshellarg to no avail (good idea though).
I should add that the file is being created through invoking
tempnam("temp", "wbsn");
The fact that it works just fine if I manually specify the string instead of letting it be generated by tempname seems to suggests that the source of the problem, but I can't figure out how. I did a comparison of the manual string with the one generated, and it came back as a match.
#exec will always fail silently, because # is PHP's error suppression operator.
Not sure if this will help you since you're on Windows and I'm on Linux, but I ran into this same problem of silent errors from PHP exec(). I figured out that the command I was attempting to issue (nconvert) sends its error messages to the standard error stream, not standard out. So I added
2>&1
at the end of the command line to redirect my error back to the standard stream. Then I could see that nconvert was giving me a permission denied error.
It could be that the PATH isn't the same from your php script vs your user account. Try removing the # and see if it's trying to throw an error.
In addition, you may want to try putting the full filesystem path to the SVN executable.
Well, if removing # isn't working, try including this at the start of the piece of code you're running:
error_reporting(E_ALL);
That'll turn on full error reporting, just in case you have it turned down or disabled in your php.ini file.
I don't suppose you could show us how exactly you're calling exec()? Could you also check to make sure you're not accidentally running the script in safe mode? Are you echoing out what exec() is returning, and if so, what is it returning?
I'm not a big fan of adding another response, but if I just edit my previous response, you may not see it.
PHP has some special escaping commands for shell scripts: escapeshellcmd and escapeshellarg.
I think you should be able to use escapeshellcmd around your entire $cmd, but I'm not sure.
Have you tried echo exec("dir") or something simple to see if exec() is working at all?
I don't know what going on, but I at least have a workaround.
This works:
$tmp = tempnam("./", "wbsn");
$filename = dirname($tmp).'\\temp\\'.basename($tmp);
This, however, does not, but I would have expected it to generate the same path (diff file name since it's a new tempnam()).
$tmp = tempnam("temp", "wbsn");
Also, this does not work, which I also would expect to generate the same thing:
$tmp = tempnam("temp", "wbsn");
$filename = dirname($tmp).'\\'.basename($tmp);
All 3 of these solutions appear to generate the same file paths, but only the first one actually works when used in my exec. I have no clue why it does not.
Visual inspection (echo) of all 3 of these appear to generate the same paths (with the exception of filenames differing, of course). A string comparison of dirname() of each of these 3 shows as a match. I have no clue what the deal is, but the first one is a workaround.
A very useful trick when debugging shell exec problems is to place an "echo" at the beginning of the command. Make sure that you can view the standard output somewhere.
This will let you examine the command for any obvious problems. Perhaps it has a wildcard that is expanding unexpectedly, or perhaps the shell quoting is not exactly right. The echo will let you see this, and you can cut and paste the echoed command into another shell to see if it is working properly.
My advice will be to switch from WIN, IIS to linux, but as alternative you can try this:
function exec_alt($cmd) {
exec($cmd, $output);
if (!$output) {
/**
* FIXME: for some reason exec() returns empty output array #mine,'s machine.
* Somehow proc_open() approach (below) works, but doesn't work at
* test machines - same empty output with both pipes and temporary
* files (not we bypass shell wrapper). So use it as a fallback.
*/
$output = array();
$handle = proc_open($cmd, array(1 => array('pipe', 'w')), $pipes, null, null, array('bypass_shell' => true));
if (is_resource($handle)) {
$output = explode("\n", stream_get_contents($pipes[1]));
fclose($pipes[1]);
proc_close($handle);
}
}
return $output; }

Categories