How to repeat the same action for diffrent variables - php

<!-- language: php -->
<?php
// test variables
$l1 = "http://youtube.com/channel/";
$l2 = "http://youtube.com/channel/";
$l3 = "http://youtube.com/channel/";
$l4 = "http://youtube.com/channel/";
$fl = "http://youtube.com/channel/";
//set error false as default
$error = "false";
//check if variables are ready for use, if they are, add them to `$l` array
//I do each check as a seperate line, as it looks cleaner than 1 long if statement.
$l = [];
if(!empty($l1)) $l[] = $l1;
if(!empty($l2)) $l[] = $l2;
if(!empty($l3)) $l[] = $l3;
if(!empty($l4)) $l[] = $l4;
if(!empty($fl)) $l[] = $fl;
foreach($l as $key => $value) {
//1 line ternary is cleaner than if/else statetmnt
$errorKey = $key < 9? "0{$key}" : $key;
//each row by default has no error
$hasError = 0;
//check if this a valid url
if(!preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $value)) {
$error = "true";
$hasError = 1;
}
if($hasError) {
//store error in array, to loop through later
$errors[] = $errorKey;
}
}
$search = '?sub_confirmation=1';
$searchUrl = "youtube.com/channel";
if (strpos($l, $searchUrl) !== false && strpos($l, $search) === false) {
$l = $value."".$search;
}
if($error == "false") {
echo $l1;
echo $l2;
echo $l3;
echo $l4;
echo $fl;
}
// deliver the error message
//Check if $error has been set to true at any point
if($error == "true") {
//loop through error array, echo error message if $errorNumber matches.
//at this point we KNOW there was an error at some point, no need to use a switch really
foreach($errors as $errorNumber) {
echo "Something went wrong here $errorNumber :o";
}
}
?>
Hello, my problem is at the end of the code where the strpos function is, so basically I want to check every url, once if it contains a certain url, and then add something to the end if it is so. But I don't want to repeat an if statement 4 times($fl variable doesn't has to be checked), I am quite new in all that so I hope somebody can help me, I tought about a switch statement but I guess there is a better way. And if I put it in the foreach aboth, it doesn't applies on the certain variables, only on the value variable.

You can assign $value by reference using this foreach header (notice the & in front of $value):
foreach($l as $key => &$value) {
By doing this every change you do to $value will also be done to the corresponding value in the $l array.
Then at the end of the foreach loop you put this code:
if (strpos($value, $searchUrl) !== false && strpos($value, $search) === false) {
$value .= $search;
}
So your final foreach loop should look like this:
foreach($l as $key => &$value) {
//1 line ternary is cleaner than if/else statetmnt
$errorKey = $key < 9? "0{$key}" : $key;
//each row by default has no error
$hasError = 0;
//check if this a valid url
if(!preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $value)) {
$error = "true";
$hasError = 1;
}
if($hasError) {
//store error in array, to loop through later
$errors[] = $errorKey;
}
$search = '?sub_confirmation=1';
$searchUrl = "youtube.com/channel";
if (strpos($value, $searchUrl) !== false && strpos($value, $search) === false) {
$value .= $search;
}
}
You can read more about using references in foreach loops here: PHP: foreach
Edit:
To apply the changes not only to the elements of the $l array, but also to the original variables $l1, $l2 and so on, you should assign the elements to your array as references too:
$l = [];
if(!empty($l1)) $l[] = &$l1;
if(!empty($l2)) $l[] = &$l2;
if(!empty($l3)) $l[] = &$l3;
if(!empty($l4)) $l[] = &$l4;
if(!empty($fl)) $l[] = &$fl;

Personally, I think this is a good candidate for moving to a class. To be honest I'm not 100% sure what you are doing but will try to convert your code to a class.
class L {
public $raw = null;
public $modified = null;
public $error = false;
// create the class
public function __construct($data=null) {
$this->raw = $data;
// Check the raw passed in data
if ($data) {
$this->isUrl();
}
// If there was no error, check the data
if (! $this->error) {
$this->search();
}
}
// Do something ?
public function debug() {
echo '<pre>';
var_dump($this);
echo '</pre>';
}
public function getData() {
return ($this->modified) ? : $this->raw;
}
private function isUrl() {
$this->error = (! preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $this->raw));
}
// Should a failed search also be an error?
private function search() {
if ($this->raw) {
if ( (strpos($this->raw, "youtube.com/channel") !== false) &&
(strpos($this->raw, "?sub_confirmation=1") === false) ) {
$this->modified = $this->raw ."?sub_confirmation=1";
}
}
}
}
// Test data
$testList[] = "test fail";
$testList[] = "https://youtube.com/searchFail";
$testList[] = "https://youtube.com/channel/success";
$testList[] = "https://youtube.com/channel/confirmed?sub_confirmation=1";
// Testing code
foreach($testList as $key=>$val) {
$l[] = new L($val);
}
foreach($l as $key=>$val) {
// Check for an error
if ($val->error) {
$val->debug();
} else {
echo '<pre>'.$val->getData().'</pre>';
}
}
And the output would be:
object(L)#1 (3) {
["raw"]=>
string(9) "test fail"
["modified"]=>
NULL
["error"]=>
bool(true)
}
https://youtube.com/searchFail
https://youtube.com/channel/success?sub_confirmation=1
https://youtube.com/channel/confirmed?sub_confirmation=1

Related

PHP if statment on array length not working

here is my code :
elseif (is_dir($dir)) {
$scanning = scandir($dir);
$okdir;
// $response["scan"] = $scanning;
foreach ($scanning as $key=> $value) {
$splitscan = explode("_",$scanning[$key]);
if ($splitscan[0] == $searchvalue ){
$okdir[] = $scanning[$key];
if (count($okdir)>1){
$response["okdir"] = $okdir;
$response["result"] = "more";
}
else {
$okdir = $okdir[0];
}
}
}
when the function goes on the else statment i get no problem, but when the conditions need to verify the if statment if(count($okdir>1)) i get PHP internal error. What does it mean? That the if statment is never true? What i'm doing wrong?
Thank you for any help provided
Here is the error log answer:
PHP Fatal error: Uncaught Error: [] operator not supported for strings
Here is the whole function:
private function pdf(){
$response;
$dir = "../Pdf/";
$searchvalue = $this->params["utentericercato"];
if (!isset($_COOKIE["idutente"])){
$response["result"] = "nosession";
$utente->setUteLogged(false);
}
// Open a known directory, and proceed to read its contents
elseif (is_dir($dir)) {
$scanning = scandir($dir);
$okdir = array();
// $response["scan"] = $scanning;
foreach ($scanning as $key=> $value) {
$splitscan = explode("_",$scanning[$key]);
if ($splitscan[0] == $searchvalue ){
$okdir[] = $scanning[$key];
if (count($okdir)>1){
$response["okdir"] = $okdir;
$response["result"] = "more";
}
else {
$okdir = $okdir[0];
}
}
}
if (empty($okdir)){
$response["result"]= "noutente";
}
else {
$newdir = $dir.$okdir;
$nomeutente = preg_replace("/[^a-zA-Z\s]/", "", $okdir);
$response["dir"] = $newdir;
$response["nomeutente"] = $nomeutente;
if (is_dir($newdir)){
$dh = array_diff(scandir($newdir),array(".",".."));
$arr = is_array($dh);
$x = 0;
while($x < sizeof($dh)){
foreach($dh as $key=>$value){
if ($key[$value] != "." && $key[$value] != ".."){
$response["files"][$key] = $value;
$response["result"] = "success";
}
$x = $x + 1;
}
}
}
}
}
else {
$response["result"] = "nodirectory";
}
Responder::giveResponse($response);
}
Your first iteration sets the variable as a string. Any subsequent iteration will attempt to "push" data into the string like it is an array.
Demo: https://3v4l.org/GOdgs
$scanning[0] = "b";
$okdir = "a"; // just add [] after $okdir
$okdir[] = $scanning[0];
var_export($okdir);
I suppose I recommend that you just remove:
else {
$okdir = $okdir[0];
}
It only causes trouble.
And...
if (count($okdir)>1){
$response["okdir"] = $okdir;
$response["result"] = "more";
}
Should be positioned after your loop so that it is executed only once.
If this were my project, I'd be doing something like chdir($dir); then glob("{$searchvalue}_*") <-- grab and filter in the same step.
I did not test it yet, however, this much cleaner approach should work. At least it should give you an idea how to do the task in a structured way.
private function pdf()
{
$response = [];
$dir = "../Pdf/";
$searchvalue = $this->params["utentericercato"];
if (is_dir($dir))
{
chdir($dir);
$okdir = glob("{$searchvalue}_*", GLOB_ONLYDIR);
switch (count($okdir))
{
case 0:
$response['result'] = 'noutente';
break;
case 1:
$nomeutente = preg_replace("/[^a-z\s]/i", "", $okdir[0]);
$response["dir"] = $dir . $okdir[0];
$response["nomeutente"] = $nomeutente;
chdir($okdir[0]);
$response["files"] = glob('*');
if(!empty($response["files"]))
{
$response["result"] = "success";
}
break;
default:
$response["okdir"] = $okdir; // or $okdir[0] if you do not want an array but the first item
$response["result"] = "more";
}
}
else
{
$response["result"] = "nodirectory";
}
Responder::giveResponse($response);
}
Here is the error log answer: PHP Fatal error: Uncaught Error: [] operator not supported for strings
To fix the error above, define $okdir as array.
Line no 3 should be changed from $okdir; to $okdir = array();
I've found the solution, old code not working:
elseif (is_dir($dir)) {
$scanning = scandir($dir);
$okdir = array();
// $response["scan"] = $scanning;
foreach ($scanning as $key=> $value) {
$splitscan = explode("_",$scanning[$key]);
if ($splitscan[0] == $searchvalue ){
$okdir[] = $scanning[$key];
if (count($okdir)>1){
$response["okdir"] = $okdir;
$response["result"] = "more";
}
else {
$okdir = $okdir[0];
}
}
}
if (empty($okdir)){
$response["result"]= "noutente";
}
new working code :
elseif (is_dir($dir)) {
$scanning = scandir($dir);
$okdir = array();
// $response["scan"] = $scanning;
foreach ($scanning as $key=> $value) {
$splitscan = explode("_",$scanning[$key]);
if ($splitscan[0] == $searchvalue ){
$okdir[] = $scanning[$key];
}
}
if (count($okdir)>1){
$response["okdir"] = $okdir;
$response["result"] = "more";
Responder::giveResponse($response);
exit;
}
if (empty($okdir)){
$response["result"]= "noutente";
}

Getting Invalid argument supplied for foreach as a result of pass by reference variable

I am upgrading a codebase that makes use of pass by reference
Main function
function splitSqlFile(&$ret, $sql)
{
$sql = trim($sql);
$sql_len = strlen($sql);
$char = '';
$string_start = '';
$in_string = false;
for ($i = 0; $i < $sql_len; ++$i) {
$char = $sql[$i];
if ($in_string) {
for (;;) {
$i = strpos($sql, $string_start, $i);
if (!$i) {
$ret[] = $sql;
return true;
}else if ($string_start == '`' || $sql[$i-1] != '\\'){
......
}else {
......
} // end if...elseif...else
} // end for
}
else if ($char == ';') {
$ret[] = substr($sql, 0, $i);
$sql = ltrim(substr($sql, min($i + 1, $sql_len)));
$sql_len = strlen($sql);
if ($sql_len) {
$i = -1;
} else {
// The submited statement(s) end(s) here
return true;
}
}else if (($char == '"') || ($char == '\'') || ($char == '`')) {
$in_string = true;
$string_start = $char;
} // end else if (is start of string)
// for start of a comment (and remove this comment if found)...
else if ($char == '#' || ($char == ' ' && $i > 1 && $sql[$i-2] . $sql[$i-1] == '--')) {
......
if (!$end_of_comment) {
// no eol found after '#', add the parsed part to the returned
// array and exit
$ret[] = trim(substr($sql, 0, $i-1));
return true;
} else {
.....
} // end if...else
} // end else if (is comment)
} // end for
// add any rest to the returned array
if (!empty($sql) && trim($sql) != '') {
$ret[] = $sql;
}
return true;
}
Calling the function
$sqlUtility->splitSqlFile($pieces, $sql_query);
foreach ($pieces as $piece)
{
.......
}
If the above variable splitSqlFile(&$ret, $sql) have the "&" before it, the program does run successfully, but if it is removed, now splitSqlFile($ret, $sql), It will start returning the 'invalid argument supplied for foreach' error.and when I try using the "is_array" function to check if it is an array, the result is always "NULL".
Why you get the error:
By removing the & from $ret, you are no longer referencing the variable in the function call. In this case, $pieces. So when you do a foreach on $pieces after calling the function, it will error because $pieces is basically a null variable at that point.
function splitSqlFile(&$ret,$sql) {
$ret[] = 'stuff';
}
splitSqlFile($pieces,$sql);
// $pieces will be an array as 0 => 'stuff'
foreach ($pieces as $piece) { } // will not error
vs:
function splitSqlFile($ret,$sql) {
$ret[] = 'stuff';
}
splitSqlFile($pieces,$sql);
// $pieces will be a null variable, since it was never assigned anything
foreach ($pieces as $piece) { } // will error
Alternative to no reference:
So if you want to remove the & and no longer pass by reference, you have to do other changes to the function to get that value back out. And depending on the codebase, this could mean a whole lot of work everywhere that function is used!
Example:
function splitSqlFile($sql) {
$ret = [];
$ret[] = 'stuff';
return array('result'=>true,'ret'=>$ret);
}
// $result will contain multiple things to utilize
// if you will only need that variable once (does not accumulate)
$result = splitSqlFile($sql);
foreach ($result['pieces'] as $piece) { }
// if that variable is added by multiple calls, and displayed later... merge
$pieces = [];
$result = splitSqlFile($sql_1);
$pieces = array_merge($pieces,$result['pieces']);
$result = splitSqlFile($sql_2);
$pieces = array_merge($pieces,$result['pieces']);
foreach ($pieces as $piece) { }
A second example (passing in the array as you go... gets confusing):
function splitSqlFile($pieces_in,$sql) {
$pieces_in[] = 'stuff';
return array('result'=>true,'pieces_out'=>$pieces_in);
}
$pieces = [];
$result = splitSqlFile($pieces,$sql_1);
$pieces = $result['pieces_out'];
$result = splitSqlFile($pieces,$sql_2);
$pieces = $result['pieces_out'];
foreach ($pieces as $piece) { }
As you can see, not only does it change the return values that has to be dealt with, but it also changes how it is called. Again, if this function is used in a thousand places in the code... serious headaches!
Conclusion:
I would honestly keep the reference as it is. It was done that way to make accumulating debug data easier, and direct. Otherwise you have a lot of code changes to do toget rid of the reference.
However that can simply be my opinion on the matter.

PHP syntax error in function, don't know why

I'm getting a syntax error and I can't figure out why. "Parse error: syntax error, unexpected '{' on line 6"
function ExtractCustomField($fieldName, $customFields) {
// $customFields might be an object, NULL, or an array.
$parsed = array();
if (is_array($customFields) == false && $customFields != null) {
$parsed = array($customFields);
} else (is_array($customFields)) {
$parsed = $customFields;
}
// loop through the fields and find the one we are looking for
$returnField = null;
foreach($field as $customFields) {
if ($field->Name == $fieldName) {
$returnField = $field;
break;
}
}
return $returnField
}
You forget to put semicolon after $returnField, also use elseif instead of else (else don't need any arguments). Use the code below
function ExtractCustomField($fieldName, $customFields) {
// $customFields might be an object, NULL, or an array.
$parsed = array();
if (is_array($customFields) == false && $customFields != null) {
$parsed = array($customFields);
} elseif (is_array($customFields)) {
$parsed = $customFields;
}
// loop through the fields and find the one we are looking for
$returnField = null;
foreach($field as $customFields) {
if ($field->Name == $fieldName) {
$returnField = $field;
break;
}
}
return $returnField;
}
Hope this helps you
else doesn't take any expression after it. Either remove the expression or use elseif instead.
You have missed semicolon in return
return $returnField;
}
Also Else condition else (is_array($customFields)) format is wrong....else dont take any condition after it...You can use Elseif instead
else (is_array($customFields)) {
Is invalid. Use either else if or remove the condition
function ExtractCustomField($fieldName, $customFields) {
// $customFields might be an object, NULL, or an array.
$parsed = array();
if (is_array($customFields) == true && $customFields != null) {
$parsed = array($customFields);
} else {
$parsed = $customFields;
}
// loop through the fields and find the one we are looking for
$returnField = null;
foreach($field as $customFields) {
if ($field->Name == $fieldName) {
$returnField = $field;
break;
}
}
return $returnField;
}
It should else if(is_array($customFields)) or elseif(is_array($customFields))
I have modified your function, i see there is supposed to be and elseif instead of else and in the foreach loop, the syntax in your code was wrong. I have also assumed that you will be using a single level associative array.
<?php
function ExtractCustomField($fieldName, $customFields) {
// $customFields might be an object, NULL, or an array.
$parsed = array();
if (is_array($customFields) == false && $customFields != null) {
$parsed = array($customFields);
} elseif (is_array($customFields)) {
$parsed = $customFields;
}
// loop through the fields and find the one we are looking for
$returnField = null;
foreach($customFields as $field) {
if ($field == $fieldName) {
$returnField = $field;
break;
}
}
return $returnField;
}
echo ExtractCustomField('name', array('name','emial','mobile','password'));
?>

in_array function, why this doesn't work?

I'm trying to validate a string to an array of numbers. If the string only contains numbers then the function should validate, but in_array isn't working, any suggestions?
$list = array(0,1,2,3,4,5,6,7,8,9);
$word = 'word';
$split = str_split($word);
foreach ($split as $s) {
if (!in_array($s, $list)) {
print 'asdf';
}
}
here is the class:
class Validate_Rule_Whitelist {
public function validate($data, $whitelist) {
if (!Validate_Rule_Type_Character::getInstance()->validate($data)) {
return false;
}
$invalids = array();
$data_array = str_split($data);
foreach ($data_array as $k => $char) {
if (!in_array($char, $whitelist)) {
$invalids[] = 'Invalid character at position '.$k.'.';
}
}
if (!empty($invalids)) {
$message = implode(' ', $invalids);
return $message;
}
return true;
}
}
in_array comparison with loosely typed values is somewhat strange. What would work in your case is:
$list = array('0','1','2','3','4','5','6','7','8','9');
$word = 'word';
$split = str_split($word);
foreach ($split as $s) {
if (!in_array($s, $list, true)) {
print 'asdf';
}
}
This compares strings with strings and results in no surprises.
But, as noted in the comments already, this is quite wrong way to do things and it is much better to use filter_var() or regular expressions** to achieve what you're trying.
it's ugly as sin but it works, no elegant solution here, just a double loop, if you see any problems please let me know
$match = array();
foreach ($data_array as $k => $char) {
foreach ($whitelist as $w) {
if (!isset($match[$k])) {
if ($char === $w) {
$match[$k] = true;
}
}
}
if (!isset($match[$k]) || $match[$k] !== true) {
$invalids[$k] = 'Invalid character at position '.$k.'.';
}
}
Something along the lines of this should work:
<?php
$validate_me = '123xyz';
if(preg_match("/[^0-9]/", $validate_me, $matches))
print "non-digit detected";
?>
update: add the $type = gettype ... settype($char, $type) to allow === to function correctly when checking for integers
foreach ($data_array as $k => $char) {
foreach ($whitelist as $w) {
if (!isset($match[$k])) {
$type = gettype($w);
if (gettype($char) !== $type) {
settype($char, $type);
}
if ($char === $w) {
$match[$k] = true;
}
}
}
...

PHP function to check if the number belongs to the interval

There is an array:
$bounds = array([0]=>array('lower'=>2,'upper'=>5),
[1]=>array('lower'=>0,'upper'=>3));
and a variable:
$val = 4;
Is there any PHP function that can say whether $val belongs to any interval defined by 'lower' and 'upper' bounds in $bounds array? In this example 4 belongs to the 1st interval [2; 5]. So, the answer should be 'true'.
I don't think there is a built-in function to do this.
However, you can do it with a foreach statement:
function check_interval($bounds, $val) {
foreach ($bounds as $array) {
if($array['lower'] <= $val && $array['upper'] >= $val)
return true;
}
return false;
}
I'm not aware of any. You'll probably have to code it. Something like this will do:
function isFromInterval($bounds, $val) {
foreach ($bounds as $value) {
if ($val >= $value['lower'] && $val <= $value['upper']) {
return true;
}
}
return false;
}
No.
You would have to make a loop for the array like this
$val = 4;
$key_id = FALSE;
foreach($bounds as $key => $data){
if($val <= $data['upper'] AND $val >= $data['lower']){
$key_id = $key;
break;
}
}
if($key_id !== FALSE){
// found something
// $bounds[$key_id] is your result in the array
} else {
// found nothing
}
As a function
function find_range($bounds=array(), $val=0, $return_key=TRUE){
if(is_array($bounds) === FALSE){
$bounds = array();
}
if(is_numeric($val) === FALSE){
$val = 0;
}
if(is_bool($return_key) === FALSE){
$return_key = TRUE;
}
$key_id = FALSE;
foreach($bounds as $key => $data){
if($val < $data['upper'] AND $val > $data['lower']){
$key_id = $key;
break;
}
}
if($key_id !== FALSE){
return ($return_key === TRUE ? $key_id : TRUE);
} else {
return FALSE;
}
}
No, but you can do:
$bounds = array(3=>array('lower'=>2,'upper'=>5),
4=>array('lower'=>0,'upper'=>3));
$val = 4;
foreach($bounds as $num => $bound){
if(max($bound) >= $val && $val >= min($bound)){
echo $num;
}
}

Categories