Please help. I'm getting this error:
( ! ) Warning: preg_match(): Unknown modifier 'b' in C:\wamp\www\pmd\install\ioncube_checker.php on line 22
When I run the following code:
function system_info($php_info) {
$server_info = array();
$server_info['thread_safe'] = 'false';
$server_info['debug_build'] = 'false';
$server_info['php_ini_path'] = '';
foreach (explode("\n",$php_info) as $line) {
if (preg_match('/command/',$line)) {
continue;
}
if (preg_match('/thread safety.*(enabled|yes)/Ui',$line)) {
$server_info['thread_safe'] = 'true';
}
if (preg_match('/debug.*(enabled|yes)/Ui',$line)) {
$server_info['debug_build'] = 'true';
}
if (preg_match("/configuration file.*(</b></td><TD ALIGN=\"left\">| => |v\">)([^ <]*)(.*</td>*)?/",$line,$match)) {
$server_info['php_ini_path'] = $match[2];
if (!#file_exists($php_ini_path)) {
$server_info['php_ini_path'] = '';
}
}
$cgi_cli = ((strpos(php_sapi_name(),'cgi') !== false) || (strpos(php_sapi_name(),'cli') !== false));
$cgi_cli ? $server_info['cgi_cli'] = 'true' : $server_info['cgi_cli'] = 'false';
}
return $server_info;
}
Since you are using / as the regex delimiter you need to escape any / with a \. However, it's much easier to use a different delimiter when dealing with HTM:
preg_match("/configuration file.*(</b></td><TD ALIGN=\"left\">| => |v\">)([^ <]*)(.*</td>*)?/",$line,$match)
should be
preg_match("#configuration file.*(</b></td><TD ALIGN=\"left\">| => |v\">)([^ <]*)(.*</td>*)?#",$line,$match)
However, you should consider not using regexes to parse HTML at all - using a DOM engine is much better for it, and PHP already has one.
Related
I have designed below code where i am using explode to explode below data,
"10.74.10.1", "10.75.10.132"
however i getting below error
"explode() expects parameter 2 to be string, array given in line.."
Can someone please suggest whats wrong in my code.
This is my full code:
public function pagesviewlogsAction()
{
// Checks authorization
$this->acl->doCheck($this);
-- language: lang-html --> // Validates request
$requestObj = new PagesviewlogEventRequest();
$requestObj->userid = (Utils::validatePattern(Utils::REGEXP_SECLOGS_USERID, (($json->userid) ?? FALSE) )) ? $json->userid:NULL;
$requestObj->clientip = array();
//if (isset($json->clientip) && $json->clientip != '' && $json->clientip != NULL) {
if (isset($json->clientip) && is_string($json->clientip)){
$tmp = explode(',', $json->clientip);
foreach ($tmp as $key => $ipValue) {
$requestObj->clientip[] = (Utils::validatePattern(Utils::REGEXP_SECLOGS_IP, ((trim($ipValue)) ?? FALSE) )) ? trim($ipValue):NULL;
}
}
}
foreach (get_object_vars($requestObj) as $key => $value) {
switch ($key) {
case 'clientip':
// ...
break;
default:
// Other cases
if ($value === FALSE) {
return new JsonModel([
'status' => 'FAILED',
'errorField' => $key,
'message'=> 'Parameters "' . $key . '" is missing or invalid.',
'data' => NULL
]);
}
break;
}
}
}
}
You condition :
if (isset($json->clientip) && $json->clientip != '' && $json->clientip != NULL)
can return true with an array.
better use something like this :
if (isset($json->clientip) && is_string($json->clientip))
The function explode() will convert a string to an array using a given separator, in your case ","
Since $json->clientip is already an array, the simple(not the best) solution is to change the code to:
$requestObj->clientip = array();
if (is_array($json->clientip)) {
foreach ($json->clientip as $key => $ipValue) {
$requestObj->clientip[] = (Utils::validatePattern(Utils::REGEXP_SECLOGS_IP, ((trim($ipValue)) ?? FALSE) )) ? trim($ipValue):NULL;
}
} else {
//handle the other option here. like string or object
}
and it depends on the source of the $json->clientip to make sure you have the correct approach in case you don't receive an array.
Exactly as it's telling you,
"10.74.10.1", "10.75.10.132" is an array. Explode requires a string because it creates an array based on the seperator ,
Try a var_dump() on your $json->clientip and see what it looks like, you may have to re-work your code a bit here.
Can I propose a possibility? I would check for both possible cases. If array execute one way, if string execute your explode.
if (!isset($json->clientip)) {
// thow exception or return call
}
$requestObj->clientip = [];
if (is_array($json->clientip)) {
array_walk($json->clientip, function($ipValue) use(&$requestObj) {
$ipValue = trim($ipValue);
$requestObj->clientip[] = (Utils::validatePattern(Utils::REGEXP_SECLOGS_IP, (($ipValue) ?? FALSE) )) ? $ipValue:NULL;
});
} else if (is_string($json->clientip)) {
// execute your explode
}
Also I would advice to check on Marshallers to help you parse logic in your code to tidy it up more instead of leaving it all into the same place. So your Utils::validatePattern could be a Marshaller in my opinion
Why do I always get a array with one item of empty string for an empty .csv file?
$content = file('products.csv');
print_r($content);
result:
Array ( [0] => )
Can I return false so that I know there is nothing in the csv file?
This seems like ad-hoc behaviour particular to your taste (no problem with that at all). Which means, you should probably create a wrapper function for this.
function contentIsNotEmpty($content) {
$isEmpty = empty($content) || (count($content) == 1 && empty($content[0]));
return $isEmpty ? false : $content;
}
EDIT: Incorporated #scrowler's feedback, and Michael J. Mulligan's.
A single line test should get you the result:
$empty = empty($content) || (count($content) === 1 && empty($content[0]));
The following should avoid the "fake empty":
$empty = empty($content) || (count($content) === 1 && $content[0] === '');
If you need a re-usable function, and prefer, as you stated, to get an array or nothing, this may be helpful:
function get_file($file_name = null, $strict = false) {
$return = null;
if(!empty($file_name) && is_readable($file_name)) {
$contents = file($file_name);
if(
!empty($contents)
&& (
count($contents) > 1
|| (
!empty($contents[0])
|| ($strict && $contents[0] !== '')
)
)
) {
$return = $contents;
}
}
return $return;
}
I mean, we could get all kinds of creative and iterate over lines, etc. But I think you get the idea.
If you want to get a CSV file, I would suggest using a method like fgetcsv() (repurposed):
function getcsv($file_name, $headers = array(), $delimiter = ',', $enclosure = '"', $escape = "\\" ) {
$contents = array();
$get_headers = $headers === FALSE;
$headers = is_array($headers) ? array_values($headers) : array();
if(!empty($file_name) && is_readable($file_name)) {
$row = 0;
if (($handle = fopen($file_name, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 0, $delimiter, $enclosure, $escape)) !== FALSE) {
if($get_headers && empty($headers)) {
$headers = $data;
continue;
}
foreach($data as $i => $col_value) {
$col_name = isset($headers[$i]) ? $headers[$i] : $i;
$contents[$row][$col_name] = $col_value;
}
$row++;
}
fclose($handle);
}
}
return $contents;
}
Note, above is not tested, just a quick draft, and I am going to bed. I'll edit it tomorrow if need be.
Finally, if you are getting a single line, with white-space, and this validates as "empty" in your eyes, simple test it after a trim:
$empty_line = trim($content[$line_num]) == '';
Not sure what else to tell you. I think we have equipped you with quite a few tools and ways to validate this situation. Best of luck.
try this
$content = file('products.csv');
if(!empty($content)){
print_r();}{
else{
// Do something if no content
}
I have the following in an INI file:
[country]
SE = Sweden
NO = Norway
FI = Finland
However, when var_dump()ing PHP's parse_ini_file() function, I get the following output:
PHP Warning: syntax error, unexpected BOOL_FALSE in test.ini on line 2
in /Users/andrew/sandbox/test.php on line 1
bool(false)
It appears that "NO" is reserved. Is there any other way I can set a variable named "NO"?
Another hack would be to reverse your ini keys with their values and use array_flip:
<?php
$ini =
"
[country]
Sweden = 'SE'
Norway = 'NO'
Finland = 'FI'
";
$countries = parse_ini_string($ini, true);
$countries = array_flip($countries["country"]);
echo $countries["NO"];
Still you will need to use quotes around NO (at least), if you do
Norway = NO
you don't get an error but value for $countries["NO"] will be an empty string.
This propably comes a little late but the way PHPs parse_ini_file works bothered me so much that I wrote my own little parser.
Feel free to use it, but use with care it has only been shallowly tested!
// the exception used by the parser
class IniParserException extends \Exception {
public function __construct($message, $code = 0, \Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
}
// the parser
function my_parse_ini_file($filename, $processSections = false) {
$initext = file_get_contents($filename);
$ret = [];
$section = null;
$lineNum = 0;
$lines = explode("\n", str_replace("\r\n", "\n", $initext));
foreach($lines as $line) {
++$lineNum;
$line = trim(preg_replace('/[;#].*/', '', $line));
if(strlen($line) === 0) {
continue;
}
if($processSections && $line{0} === '[' && $line{strlen($line)-1} === ']') {
// section header
$section = trim(substr($line, 1, -1));
} else {
$eqIndex = strpos($line, '=');
if($eqIndex !== false) {
$key = trim(substr($line, 0, $eqIndex));
$matches = [];
preg_match('/(?<name>\w+)(?<index>\[\w*\])?/', $key, $matches);
if(!array_key_exists('name', $matches)) {
throw new IniParserException("Variable name must not be empty! In file \"$filename\" in line $lineNum.");
}
$keyName = $matches['name'];
if(array_key_exists('index', $matches)) {
$isArray = true;
$arrayIndex = trim($matches['index']);
if(strlen($arrayIndex) == 0) {
$arrayIndex = null;
}
} else {
$isArray = false;
$arrayIndex = null;
}
$value = trim(substr($line, $eqIndex+1));
if($value{0} === '"' && $value{strlen($value)-1} === '"') {
// too lazy to check for multiple closing " let's assume it's fine
$value = str_replace('\\"', '"', substr($value, 1, -1));
} else {
// special value
switch(strtolower($value)) {
case 'yes':
case 'true':
case 'on':
$value = true;
break;
case 'no':
case 'false':
case 'off':
$value = false;
break;
case 'null':
case 'none':
$value = null;
break;
default:
if(is_numeric($value)) {
$value = $value + 0; // make it an int/float
} else {
throw new IniParserException("\"$value\" is not a valid value! In file \"$filename\" in line $lineNum.");
}
}
}
if($section !== null) {
if($isArray) {
if(!array_key_exists($keyName, $ret[$section])) {
$ret[$section][$keyName] = [];
}
if($arrayIndex === null) {
$ret[$section][$keyName][] = $value;
} else {
$ret[$section][$keyName][$arrayIndex] = $value;
}
} else {
$ret[$section][$keyName] = $value;
}
} else {
if($isArray) {
if(!array_key_exists($keyName, $ret)) {
$ret[$keyName] = [];
}
if($arrayIndex === null) {
$ret[$keyName][] = $value;
} else {
$ret[$keyName][$arrayIndex] = $value;
}
} else {
$ret[$keyName] = $value;
}
}
}
}
}
return $ret;
}
What does it differently? Variable names may only consist of alphanumerical characters but other than that no restrictions to them. Strings must be encapsulated with " everything else has to be a special value like no, yes, true, false, on, off, null or none. For mapping see code.
Kind of a hack but you can add backticks around the key names:
[country]
`SE` = Sweden
`NO` = Norway
`FI` = Finland
Then access them like so:
$result = parse_ini_file('test.ini');
echo "{$result['`NO`']}\n";
Output:
$ php test.php
Norway
I was getting this error when there were single quote combinations in the string such as 't or 's. To get rid of the problem, I wrapped the string in double quotes:
Before:
You have selected 'Yes' but you haven't entered the date's flexibility
After:
"You have selected 'Yes' but you haven't entered the date's flexibility"
I ran into the same problem and tried to escape the name in every possible way.
Then I remembered that because of the INI syntax both names and values will be trimmed, so the following workaround MAYBE should do the trick:
NL = Netherlands
; A whitespace before the name
NO = Norway
PL = Poland
And it works ;) As long as your co-workers read the comments (which is not always the case) and don't delete it accidentally. So, yes, the array flipping solution is a safe bet.
From the manual page for parse_ini_file:
There are reserved words which must not be used as keys for ini files. These include: null, yes, no, true, false, on, off, none.
So no, you can't set a variable NO.
I have a plugin that uses strpos() method and on one site I'm getting this error
Warning: strpos() [function.strpos]: Empty delimiter. in /home/mysite/public_html/wp-includes/compat.php on line 55
Any ideas what the likely cause of this could be?
excerpt from compat.php
if (!function_exists('stripos')) {
function stripos($haystack, $needle, $offset = 0) {
return strpos(strtolower($haystack), strtolower($needle), $offset);
}
}
My code...
function myFunction($thePost)
{
$theContent = $thePost->post_content;
$myVar1 = array();
preg_match_all('/<a\s[^>]*href=\"([^\"]*)\"[^>]*>(.*)<\/a>/siU',$theContent,$myVar1);
$myVar2 = 0;
foreach ($myVar1[1] as $myVar3)
{
$myVar4 = $myVar1[2][$myVar2];
$myVar5 = FALSE;
$myVar6 = get_bloginfo('wpurl');
$myVar7 = str_replace('http://www.','',$myVar3);
$myVar7 = str_replace('http://','',$myVar7);
$myVar8 = str_replace('http://www.','',$myVar6);
$myVar8 = str_replace('http://','',$myVar8);
if (strpos($myVar3,'http://')!==0 || strpos($myVar7,$myVar8)===0) return TRUE;
$myVar2++;
}
return FALSE;
}
Something is passing an empty string as the second argument to Wordpress' implementation of stripos() (and it's not the code you've pasted above).
Can I ask why you a using PHP 4?
TRY ADDING double quotes on the on the variable
change this line:
if (strpos($myVar3,'http://')!==0 || strpos($myVar7,$myVar8)===0) return TRUE;
into:
if (strpos(".$myVar3.",'http://')!==0 || strpos(".$myVar7.",".$myVar8.")===0) return TRUE;
I am very new to regex, and this is way too advanced for me. So I am asking the experts over here.
Problem
I would like to retrieve the constants / values from a php define()
DEFINE('TEXT', 'VALUE');
Basically I would like a regex to be able to return the name of constant, and the value of constant from the above line. Just TEXT and VALUE . Is this even possible?
Why I need it? I am dealing with language file and I want to get all couples (name, value) and put them in array. I managed to do it with str_replace() and trim() etc.. but this way is long and I am sure it could be made easier with single line of regex.
Note: The VALUE may contain escaped single quotes as well. example:
DEFINE('TEXT', 'J\'ai');
I hope I am not asking for something too complicated. :)
Regards
For any kind of grammar-based parsing, regular expressions are usually an awful solution. Even smple grammars (like arithmetic) have nesting and it's on nesting (in particular) that regular expressions just fall over.
Fortunately PHP provides a far, far better solution for you by giving you access to the same lexical analyzer used by the PHP interpreter via the token_get_all() function. Give it a character stream of PHP code and it'll parse it into tokens ("lexemes"), which you can do a bit of simple parsing on with a pretty simple finite state machine.
Run this program (it's run as test.php so it tries it on itself). The file is deliberately formatted badly so you can see it handles that with ease.
<?
define('CONST1', 'value' );
define (CONST2, 'value2');
define( 'CONST3', time());
define('define', 'define');
define("test", VALUE4);
define('const5', //
'weird declaration'
) ;
define('CONST7', 3.14);
define ( /* comment */ 'foo', 'bar');
$defn = 'blah';
define($defn, 'foo');
define( 'CONST4', define('CONST5', 6));
header('Content-Type: text/plain');
$defines = array();
$state = 0;
$key = '';
$value = '';
$file = file_get_contents('test.php');
$tokens = token_get_all($file);
$token = reset($tokens);
while ($token) {
// dump($state, $token);
if (is_array($token)) {
if ($token[0] == T_WHITESPACE || $token[0] == T_COMMENT || $token[0] == T_DOC_COMMENT) {
// do nothing
} else if ($token[0] == T_STRING && strtolower($token[1]) == 'define') {
$state = 1;
} else if ($state == 2 && is_constant($token[0])) {
$key = $token[1];
$state = 3;
} else if ($state == 4 && is_constant($token[0])) {
$value = $token[1];
$state = 5;
}
} else {
$symbol = trim($token);
if ($symbol == '(' && $state == 1) {
$state = 2;
} else if ($symbol == ',' && $state == 3) {
$state = 4;
} else if ($symbol == ')' && $state == 5) {
$defines[strip($key)] = strip($value);
$state = 0;
}
}
$token = next($tokens);
}
foreach ($defines as $k => $v) {
echo "'$k' => '$v'\n";
}
function is_constant($token) {
return $token == T_CONSTANT_ENCAPSED_STRING || $token == T_STRING ||
$token == T_LNUMBER || $token == T_DNUMBER;
}
function dump($state, $token) {
if (is_array($token)) {
echo "$state: " . token_name($token[0]) . " [$token[1]] on line $token[2]\n";
} else {
echo "$state: Symbol '$token'\n";
}
}
function strip($value) {
return preg_replace('!^([\'"])(.*)\1$!', '$2', $value);
}
?>
Output:
'CONST1' => 'value'
'CONST2' => 'value2'
'CONST3' => 'time'
'define' => 'define'
'test' => 'VALUE4'
'const5' => 'weird declaration'
'CONST7' => '3.14'
'foo' => 'bar'
'CONST5' => '6'
This is basically a finite state machine that looks for the pattern:
function name ('define')
open parenthesis
constant
comma
constant
close parenthesis
in the lexical stream of a PHP source file and treats the two constants as a (name,value) pair. In doing so it handles nested define() statements (as per the results) and ignores whitespace and comments as well as working across multiple lines.
Note: I've deliberatley made it ignore the case when functions and variables are constant names or values but you can extend it to that as you wish.
It's also worth pointing out that PHP is quite forgiving when it comes to strings. They can be declared with single quotes, double quotes or (in certain circumstances) with no quotes at all. This can be (as pointed out by Gumbo) be an ambiguous reference reference to a constant and you have no way of knowing which it is (no guaranteed way anyway), giving you the chocie of:
Ignoring that style of strings (T_STRING);
Seeing if a constant has already been declared with that name and replacing it's value. There's no way you can know what other files have been called though nor can you process any defines that are conditionally created so you can't say with any certainty if anything is definitely a constant or not nor what value it has; or
You can just live with the possibility that these might be constants (which is unlikely) and just treat them as strings.
Personally I would go for (1) then (3).
This is possible, but I would rather use get_defined_constants(). But make sure all your translations have something in common (like all translations starting with T), so you can tell them apart from other constants.
Try this regular expression to find the define calls:
/\bdefine\(\s*("(?:[^"\\]+|\\(?:\\\\)*.)*"|'(?:[^'\\]+|\\(?:\\\\)*.)*')\s*,\s*("(?:[^"\\]+|\\(?:\\\\)*.)*"|'(?:[^'\\]+|\\(?:\\\\)*.)*')\s*\);/is
So:
$pattern = '/\\bdefine\\(\\s*("(?:[^"\\\\]+|\\\\(?:\\\\\\\\)*.)*"|\'(?:[^\'\\\\]+|\\\\(?:\\\\\\\\)*.)*\')\\s*,\\s*("(?:[^"\\\\]+|\\\\(?:\\\\\\\\)*.)*"|\'(?:[^\'\\\\]+|\\\\(?:\\\\\\\\)*.)*\')\\s*\\);/is';
$str = '<?php define(\'foo\', \'bar\'); define("define(\\\'foo\\\', \\\'bar\\\')", "define(\'foo\', \'bar\')"); ?>';
preg_match_all($pattern, $str, $matches, PREG_SET_ORDER);
var_dump($matches);
I know that eval is evil. But that’s the best way to evaluate the string expressions:
$constants = array();
foreach ($matches as $match) {
eval('$constants['.$match[1].'] = '.$match[1].';');
}
var_dump($constants);
You might not need to go overboard with the regex complexity - something like this will probably suffice
/DEFINE\('(.*?)',\s*'(.*)'\);/
Here's a PHP sample showing how you might use it
$lines=file("myconstants.php");
foreach($lines as $line) {
$matches=array();
if (preg_match('/DEFINE\(\'(.*?)\',\s*\'(.*)\'\);/i', $line, $matches)) {
$name=$matches[1];
$value=$matches[2];
echo "$name = $value\n";
}
}
Not every problem with text should be solved with a regexp, so I'd suggest you state what you want to achieve and not how.
So, instead of using php's parser which is not really useful, or instead of using a completely undebuggable regexp, why not write a simple parser?
<?php
$str = "define('nam\\'e', 'va\\\\\\'lue');\ndefine('na\\\\me2', 'value\\'2');\nDEFINE('a', 'b');";
function getDefined($str) {
$lines = array();
preg_match_all('#^define[(][ ]*(.*?)[ ]*[)];$#mi', $str, $lines);
$res = array();
foreach ($lines[1] as $cnt) {
$p = 0;
$key = parseString($cnt, $p);
// Skip comma
$p++;
// Skip space
while ($cnt{$p} == " ") {
$p++;
}
$value = parseString($cnt, $p);
$res[$key] = $value;
}
return $res;
}
function parseString($s, &$p) {
$quotechar = $s[$p];
if (! in_array($quotechar, array("'", '"'))) {
throw new Exception("Invalid quote character '" . $quotechar . "', input is " . var_export($s, true) . " # " . $p);
}
$len = strlen($s);
$quoted = false;
$res = "";
for ($p++;$p < $len;$p++) {
if ($quoted) {
$quoted = false;
$res .= $s{$p};
} else {
if ($s{$p} == "\\") {
$quoted = true;
continue;
}
if ($s{$p} == $quotechar) {
$p++;
return $res;
}
$res .= $s{$p};
}
}
throw new Exception("Premature end of line");
}
var_dump(getDefined($str));
Output:
array(3) {
["nam'e"]=>
string(7) "va\'lue"
["na\me2"]=>
string(7) "value'2"
["a"]=>
string(1) "b"
}