php if behaves different in windows and linux - php

Recently I came to know that there is a slight difference in code behavior due to host platform.
$result = Data::my_custom_function($data, 'id');
//comment : my_custom_function($array, $id) --- it will return either false or string based on business logic
if($result)
{
return $result;
}
else
{
return false;
}
Above code runs fine with Windows if STRING is returned by function, but the same is not happening on CentOS server where the project is hosted.
It goes to else part even if there is string in $result variable.
I had to change the code to follow to have it run on both:
if(!empty($result) && is_string($result) && strlen($result) > 0)
{
return $result;
}
else
{
return false;
}
Why it happened I have no idea. Maybe because Windows is bit soft on strict policy like file name you can write on upper/lower case it goes without issue but in Linux kernel filename must be exactly in lower/upper case as it is on the file system.
Please help.
System Info:
Both server and Local machine are equipped with PHP-7.4.x
Localhost is Windows 10
Server is Cent OS 7.x

Related

Unusual error in code igniter system file when deployed to a VPS server

I recently finished building my site using code igniter on WAMP local server and tested it on a shared hosting server (from Namecheap). Then I got VPS hosting plan (from iPage) and uploaded the files and did the necessary configs. However, I got this error when I tried accessing the site:
An uncaught Exception was encountered
Type: Error
Message: Call to undefined function ctype_digit()
Filename: /home/eastngco/public_html/system/core/Security.php
Line Number: 600
Problem is, the suspect file, Security.php, is a code igniter system file which I never messed with (everything I wrote was within the application folder). Below is a code snippet around the line in Security.php causing the error:
/**
* Get random bytes
*
* #param int $length Output length
* #return string
*/
public function get_random_bytes($length)
{
if (empty($length) OR ! ctype_digit((string) $length))
{
return FALSE;
}
if (function_exists('random_bytes'))
{
try
{
// The cast is required to avoid TypeError
return random_bytes((int) $length);
}
catch (Exception $e)
{
// If random_bytes() can't do the job, we can't either ...
// There's no point in using fallbacks.
log_message('error', $e->getMessage());
return FALSE;
}
}
// Unfortunately, none of the following PRNGs is guaranteed to exist ...
if (defined('MCRYPT_DEV_URANDOM') && ($output = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)) !== FALSE)
{
return $output;
}
if (is_readable('/dev/urandom') && ($fp = fopen('/dev/urandom', 'rb')) !== FALSE)
{
// Try not to waste entropy ...
is_php('5.4') && stream_set_chunk_size($fp, $length);
$output = fread($fp, $length);
fclose($fp);
if ($output !== FALSE)
{
return $output;
}
}
if (function_exists('openssl_random_pseudo_bytes'))
{
return openssl_random_pseudo_bytes($length);
}
return FALSE;
}
I have no idea what random bytes or ctype_digit() means!
I did some digging on the web to see if a similar problem (and its solution) would pop, but nothing did. I need help fixing this please.
If it means anything, the PHP version that comes with my hosting plan is version 7, and I have SSL.
Ipage has a support page to enable the ctype extension, please read this article, using code igniter and PHP: 7.4.10, I receive this error message: Call to undefined function ctype_digit().
Enabling this extension in Ipage the problem was solved in my case.
Article:
https://www.ipage.com/help/article/how-to-enable-ctype-so-extensions-in-php-ini
Looks like your provider might have explicitly disabled those types of functions. It should be enabled by default. Try contacting your provider for some support on enabling these, or reinstalling PHP without that flag turned off.
http://us2.php.net/manual/en/ctype.installation.php
Additionally, you could try and inspect a phpinfo() page to confirm whether ctypes are enabled or not. It seems weird that they would turn it off, so this would help figure out if this is part of the issue.

How to calculate number of processor cores in PHP script (linux)?

I'm trying to use pthreads for multithreading. I'm creating pool with constructor. First parameter is number of Workers.
$pool = new Pool(8, 'WebWorker');
I want to detect count of processor cores automatically. Something like this:
$pool = new Pool(get_processor_cores_number(), 'WebWorker');
How is it possible with PHP?
If the server is a Linux machine you can do it with the following snippet:
$ncpu = 1;
if(is_file('/proc/cpuinfo')) {
$cpuinfo = file_get_contents('/proc/cpuinfo');
preg_match_all('/^processor/m', $cpuinfo, $matches);
$ncpu = count($matches[0]);
}
You can do something like that, of course your server should be in linux:
function get_processor_cores_number() {
$command = "cat /proc/cpuinfo | grep processor | wc -l";
return (int) shell_exec($command);
}
You will execute a shell command then cast it to int.
In case anyone looking for a easy function to get total CPU cores for Windows and Linux both OS.
function get_processor_cores_number() {
if (PHP_OS_FAMILY == 'Windows') {
$cores = shell_exec('echo %NUMBER_OF_PROCESSORS%');
} else {
$cores = shell_exec('nproc');
}
return (int) $cores;
}
Here is an extension exposing sysconf: krakjoe/sysconf
<?php
$cpusConfigured = sysconf(SYSCONF_NPROCESSORS_CONF);
$cpusOnline = sysconf(SYSCONF_NPROCESSORS_ONLN);
?>
Most applications only care about the number configured.
In my own library, I have a function for this among other things. You can easily modify it where it uses nonstandard PHP functions.
For instance, I cache the result so you can ignore that. Then I have functions to check if we are running on Linux, Mac or Windows. You could insert a similar check of your own there. For executing the actual system specific check I use my own Process class which allows things such as reconnecting to running processes on subsequent requests to check status, output etc. But you can change that and just use exec.
public static function getNumberOfLogicalCPUCores() {
$numCores = CacheManager::getInstance()->fetch('System_NumberOfLogicalCPUCores');
if(!$numCores) {
if(System::isLinux() || System::isMac()) {
$getNumCoresProcess = new Process("grep -c ^processor /proc/cpuinfo");
$getNumCoresProcess->executeAndWait();
$numCores = (int)$getNumCoresProcess->getStdOut();
}
else if(System::isWindows()) {
// Extract system information
$getNumCoresProcess = new Process("wmic computersystem get NumberOfLogicalProcessors");
$getNumCoresProcess->executeAndWait();
$output = $getNumCoresProcess->getStdOut();
// Lazy way to avoid doing a regular expression since there is only one integer in the output on line 2.
// Since line 1 is only text "NumberOfLogicalProcessors" that will equal 0.
// Thus, 0 + CORE_COUNT, which equals CORE_COUNT, will be retrieved.
$numCores = array_sum($getNumCoresProcess->getStdOutAsArray());
}
else {
// Assume one core if this is some unkown OS
$numCores = 1;
}
CacheManager::getInstance()->store('System_NumberOfLogicalCPUCores', $numCores);
}
return $numCores;
}
Avoid spinning up a whole new shell to get simple information out of the OS when you can. This is extremely slow and is a memory hog as you're spawning an entire command interpreter for a single simple task.
Here is a quick function to do it on Linux or Windows that doesn't require spawning a whole new shell:
function get_total_cpu_cores() {
return (int) ((PHP_OS_FAMILY == 'Windows')?(getenv("NUMBER_OF_PROCESSORS")+0):substr_count(file_get_contents("/proc/cpuinfo"),"processor"));
}
This will work on any semi-modern windows installation (since at LEAST Windows 95) and will work on most, if not all, flavors of Linux assuming you have the rights to read /proc/cpuinfo. But most installations make that world readable... so shouldn't have any problems.
Further note to bear in mind technically this is showing you the CPU cores available as the OS sees it. Both Windows and Linux see hyperthreaded CPU threads as cores even though they aren't physical cores. That said, this should still work for what you're trying to do unless you REALLY need to know the number of physical cores on a machine. Then you're in for a more involved process.
Hope this helps!

Why is_dir() function is not working for Network paths in PHP?

I am checking in my code, if directory exists or not with is_dir().
It works for local drives, but not for network paths.
Can anyone help me out?
Here Is My Sample Code:
public function setXMLFilePath($filePath) {
if(is_dir($filePath)) {
$this->XMLFilePath = $filePath;
$retVal = true;
} else {
$ratVal = false;
}
return $retVal;
}//setXMLFilePath
And My Network Path is Like this:
$filePath = '\\Nas-heidi\heidi\FAS\Polish GameRobot\Export_Raffle\';
The file-related functions wrap over a few protocols, the Windows networking schema is not one of them.
Also notable is the fact that when you are accessing one of these (external) protocols you should not be using shorthands such as \\\network_computer\network_folder\ you should be using full protocol specifications such as ftp:///http:///ssh:// and if the protocol for Windows networking existed it would probably have such an identifier.
This is probably because the account that run PHP script (maybe the count that start the Apache service) has no permissions for such directories.

php exec() responding differently from windows 8 metro app

I wanted to change the tile icons for desktop applications in the new windows 8 start menu.
So they would fit in with the other metro apps.
I made a simple metro app that calls a simple localhost php file
<?php
// check if the chrome is in the task list
exec('tasklist /FI "IMAGENAME eq chrome.exe" 2>NUL | find /I /N "chrome.exe">NUL');
// get a return value I can check
$runing = exec('if "%ERRORLEVEL%"=="0" echo Programm is running');
if ($runing === 'Programm is running'){
// the program is open already
echo $runing;
} else {
// the program is not running and should be opened
exec('C:\Users\Gerdy\AppData\Local\Google\Chrome\Application\chrome.exe');
}
?>
If I launch this file from chrome it echos "Programm is running".
That's great!
If I launch it from windows start and Chrome is not running, Chrome does not start.
If I exclude the if statement and just run.
exec('C:\Users\Gerdy\AppData\Local\Google\Chrome\Application\chrome.exe');
From the start menu.
It will open a new Chrome window regardless of if chrome is already open.
So I guess my question is :
What can I do that will allow my php file to check if chrome is open and if it is not , to open it?
This model actually works for any other program just not browsers.
My best guess is that it has do less with my commands and more to do with chrome itself.
It could be a target that I need to add, I don't know.
You can use Windows Management Instrumentation:
If you have not used wmic before you should install it by running wmic from cmd.exe.
It should then say something like:
WMIC Installing... please wait.
After that wmic is ready for use:
function getProcessId( $imagename ) {
ob_start();
passthru('wmic process where (name="'.$imagename.'") get ProcessId');
$wmic_output = ob_get_contents();
ob_end_clean();
// Remove everything but numbers and commas between numbers from output:
$wmic_output = preg_replace(
array('/[^0-9\n]*/','/[^0-9]+\n|\n$/','/\n/'),
array('','',','),
$wmic_output );
if ($wmic_output != '') {
// WMIC returned valid PId, should be safe to convert to int:
$wmic_output = explode(',', $pids);
foreach ($wmic_output as $k => $v) { $wmic_output[$k] = (int)$v; }
return $wmic_output;
} else {
// WMIC did not return valid PId
return false;
}
}
// Find out process id's:
if ($pids = getProcessId( "chrome.exe" )) {
foreach ($pids as $pid) {
echo "Chrome.exe is running with pid $pid";
}
} else {
echo "Chrone.exe is not running";
}
I have not tested this and just wrote it out of my head so there might be some fixing and you should check wmic's output by running it from commandline with same args to see if preg_replace() is doing it right (get pid from wmic's output).
UPDATE:
Tested and it seems that wmic does not return any status codes so updated my php function to reflect this bahavior.
UPDATE:
Now it handles multiple processes too and returns all pids as indexed array or false when no process running.
About WMI:
Windows Management Instrumentation is very powerful interface and so is wmic commandline tool. Here is listed some of WMI features

Identify development vs. production server in PHP

I work with two application servers on a daily basis: one development, one production. A variety of apps from different developers live on these boxes, as well as some scripts that run via cron. Currently, I am using the -D flag to httpd so that I can identify my production server in code, ie. isset($_SERVER['DEV']). Unfortunately, this does not work for scripts run from the command line since they're not under the Apache umbrella.
Essentially, I would like a clean, simple way to identify development vs. production that is available to every line of code.
What I have ruled out:
auto_prepend_file -- we are already using this directive in some applications, and you can't have more than one autoprepend.
What I am currently exploring:
Custom extension -- I'm sure creating a new extension that only defines a new constant (possibly influenced by an ini setting) would not be the hardest thing in the world, but I have no prior experience in this area.
So, got any tricks for identifying dev/prod that doesn't involve injecting code into every script or application?
use an environment variable
Just set an environment variable. It works on Windows and linux, they are even called the same thing now. Then just check $_ENV["DEVVSPROD"]
I usually just do something like this:
if ($_SERVER['HTTP_HOST'] == 'localhost') // or any other host
{
// development
}
else
{
// production
}
I ended up using $_ENV['HOSTNAME'], with php_uname("n") as a backup:
/**
* Returns true if we are working on a development server, determined by server's
* hostname. Will generate an error if run on an unknown host.
*/
public static function isdev()
{
static $isdev = null;
// don't run function body more than once
if( null !== $isdev ) {
return $isdev;
}
// prefer HOSTNAME in the environment, which will be set in Apache.
// use `uname -n' as a backup.
if( isset( $_ENV['HOSTNAME'] ) ) {
$hostname = $_ENV['HOSTNAME'];
} else {
$hostname = php_uname("n");
}
switch( $hostname ) {
case 'production1.example.com':
case 'production2.example.com':
case 'production3.example.com': $isdev = false; break;
case 'dev1.example.com':
case 'dev2':
case 'dev2.example.com': $isdev = true; break;
default: trigger_error( 'HOSTNAME is set to an unknown value', E_USER_ERROR );
}
return $isdev;
}
This came to my mind
if(filter_var(ini_get('display_errors'), FILTER_VALIDATE_BOOLEAN))
{
// development
}
else {
// production
}
or a better approach
define('IN_DEVELOPEMENT', filter_var(ini_get('display_errors'), FILTER_VALIDATE_BOOLEAN));
A company I worked for previously used a convention of suffixing servers as follows:
L = Live
D = Dev
T = Test
U = UAT
This makes determining the environment that you're working on, both inside and outside of Apache, fairly trivial.

Categories