PHP: undefined offset in explode() - php

I have this:
list($firstname, $lastname) = explode(' ', $queryString);
Sometiems $lastname does not gets defined, and it's there i am getting undefined offset error.
Because it can not find anything to put in $lastname, i guess.
After the explode() i have:
if(!$lastname) { $lastname = $firstname; }
So my question is how can i define it as the $firstname if $lastname is not defined (if you wrote only 'Adam' and not 'Adam Thompson', the lastname should be defined so it is 'Adam Adam')
It does this for me now, but I am receiving the offset error

list($firstname, $lastname) = array_pad(explode(' ', $queryString, 2), 2, null);
The 2 in explode() ensures, that there are at most 2 values and array_pad() ensures, that there are at least 2 values. If there is no space character , $lastname is null. This you can use to decide what comes next
$lastname = is_null($lastname) ? $firstname : $lastname;
Little update: For this specific case you can use a little trick
list($firstname, $lastname) = array_pad(explode(' ', $queryString, 2), 2, $queryString);
This will do all that in one step. It should work, because
There is always at least one value (for $firstname)
If there is one value, then $queryString == $firstname. Thats now the value that is used to fill the array up to 2 values (which is exactly one, because one value we already have)
If there are two values, then the array is not filled with $queryString, because we already have 2 values
At least for readability I would prefer the first more obvious solution.

Try appending a space:
list($firstname, $lastname) = explode(' ', $queryString . ' ' );
shouldn't have to change a thing after that.

You're not getting an Error, but a Notice.
Although this is acceptable since PHP is a dynamic language, you can prevent it with isset():
if(!isset($lastname)) {
$lastname = $firstname;
}
UPDATE
Per the comments, list() is the culprit for the Notice. In which case, I wouldn't recommend the use of list() when explode() doesn't yield the appropriate number of parameters.
If you must, the answer by brady or undefined offset when using php explode() can work. Although it's pretty ugly in my opinion. I believe your code would be much more intuitive if you just did the following:
$name = explode(' ', $queryString);
if (isset($name[1])) {
// show lastname
}
else {
// show firstname
}

I just ran into this today. my solution was not the above,
(which had no effect) mine was the following:
while (!feof($fh))
{
$line = fgets($fh);
print $line;
}
instead of doing:
while ($line = fgets($fh))
{
print $line;
}

I'm not clear why this works, but the notice will go away. First, with this code I get the undefined offset notice:
list($month, $day, $year)=explode('-', $dateToChange, 3);
However, with this code, I don't:
list($month, $day, $year, $junk)=explode('-', $dateToChange.'---', 4);
Also note, with '-' or '--' appended to $dateToChange, I will get the offset notice. It takes three dashes for it to go away in my example with four variables. $junk contains the two dashes (one being a separator).

Related

Dynamically generating variable names to be used in the bind_param() function of a PHP prepared statement

I was wondering if it's possible to store the variables to be inserted in a bind_param() function inside another variable such that if this were the original query:
$stmt->bind_param("si", $column1, $column2);
would it be possible to store the 2 variables inside another variable, i.e:
$columns = $column1.','.$column2;
And then if the new variable can be used inside the bind_param() function like this such that it works:
$stmt->bind_param("si", $columns);
My Database column names and php variable names are the same (except for the '$' sign of course), so I tried this:
$string = "column1, column2";
function convert_to_variables($string) {
// Convert column names to an array
$array = explode(", ", $string);
// Convert column names array values to a variable
foreach ($array as $key => $value) {
$array_values_with_dollar[] = $$value; // (previously tried with '$'.$value)
}
// Convert to string again
$imploded = implode(", ", $array_values_with_dollar);
return $imploded;
}
.
.
$variables = convert_to_variables($string);
.
.
$stmt->bind_param("si", $variables );
.
.
// Everything else like $stmt = $dbc->prepare(""); and $stmt->execute(); etc exists.
// The bind_param() is the only line with an error.
(Right now I'm getting an 'Undefined variable: column1' error.)
It's not possible to do with strings directly, because it'd be interpreted as just that - a single string, and not a combination of strings that'd make up the values for each column. Using that logic, you'd also have issues if one of your strings actually contains ', 'as well - then it wouldn't match up with number of values and number of parameters.
I can suggest an alternative using arrays instead. You can use that string as a base if you really need to, and use explode() on that. In any case, using an array, you can use the "unpacking operator" ... to unpack the array.
$string = "column1, column2";
$boom = explode(", ", $string);
$stmt->bind_param("ss", ...$boom);
Alternatively build it as an array, and use that (which effectively is the same). This approach is better, as it will not produce more values than parameters if one or more of the strings contains a comma ,.
$variables = array("column1", "column2");
$stmt->bind_param("ss", ...$variables);
PHP 'New Features' on array unpacking
Also note that I've changed "types" parameter to ss (was si), because both your parameters are in fact strings.
Is this what you want? Creates variables called $column1 , 2 etc. From string.
$string = "column1, column2, boo3";
$arr = explode(", ", $string);
Foreach($arr as $var){
$$var = $var;
}
Echo $column1 . $column2 . $boo3;
https://3v4l.org/sW0cu
Double $ will grab the variables value and use that as name for the variable.

comma separated if value in array is empty

I am stuck with a problem, I have fetched some values from a MySQL query and put them in to an array like so:
$add1 = $location->address1;
$add2 = $location->address2;
$twn = $location->town;
$pcode = $location->postcode;
$latitude = $location->lat;
$longitude = $location->lng;
$fullAddress = [$add1, $add2, $twn, $pcode];
$string = rtrim(implode(',', $fullAddress), ',');
echo $string;
so that I can echo out a users address. The problem I am getting is that even if one of these values does not exist (and some don't because they are not all required fields), the comma is still echoed to the screen like:
add1,, town, br2 5lp
because there is an empty value in the database.
What I want to achieve is something like:
add1, town, br2 5lp
if the second part of the address is missing.
Can anyone help me figure this out?
try this.
$fullAddress = [$add1, $add2, $twn, $pcode];
$string = implode(',', array_filter($fullAddress, 'strlen'));
echo $string;
The problem I am getting is that even if one of these values does not
exist (and some dont because they are not all required fields),
the comma is still echoed to the screen
That is what the implode function in php is supposed to do. If you want a different behavior, you will have to either change the way you create your CSV string or do some extra processing on the information you obtain from the implode function.
So use a for loop or a foreach loop to go through the address array. A for loop is faster than a foreach loop.
Using Foreach:
$add1 = $location->address1;
$add2 = $location->address2;
$twn = $location->town;
$pcode = $location->postcode;
$latitude = $location->lat;
$longitude = $location->lng;
$fullAddress = [$add1, $add2, $twn, $pcode];
$string = "";
foreach($fullAddress as $value)
{
if(!empty($value))
$string .= $value.", ";
}
$string = rtrim($string, ", ");
echo $string;
You can do some extra processing on the created csv string of your own solution by maybe doing a str_replace() of all occurances of ,, with ,. This could be dangerous because if any of the values in your $fullAddress array contain a ,, as a valid string then that will also be replaced too with ,.
What you need is to assure array $fullAddress have no empty value, so php built-in function array_filter make this purpose very easy.
Just change your last codes to:
$string = implode(',', array_filter($fullAddress));
echo $string;
If the second parameter of array_filter is not supplied, all entries of array equal to FALSE will be removed. So just simply use array_filter($fullAddress) it make the code more clear and simple.

Php split a string to to string

I want to split a variable that I call for $ NowPlaying which contains the results of the current song. I would now like to share the following - so I get two new variables containing $ artist $ title. Having searched and tried to find a solution, but have stalled grateful for a little assistance, and help
<?php
// Assuming $NowPlaying is something like "J. Cole - Chaining Day"
// $array = explode("-", $NowPlaying); //enter a delimiter here, - is the example
$array = explode(" - ", $NowPlaying); //DJHell pointed out this is better
$artist = $array[0]; // J. Cole
$song = $array[1]; // Chaining Day
// Problems will arise if the delimiter is simply (-), if it is used in either
// the song or artist name.. ie ("Jay-Z - 99 Problems") so I advise against
// using - as the delimiter. You may be better off with :.: or some other string
?>
Sounds like you're wanting to use explode()
http://php.net/manual/en/function.explode.php
Use php explode() function
$str_array = explode(' - ', $you_song);
// then you can get the variables you want from the array
$artist = $str_array[index_of_artist_in_array];
$title = $str_array[index_of_title_in_array];
I would usually do some thing like this:
<?php
$input = 'Your - String';
$separator = ' - ';
$first_part = substr($input, 0, strpos($input, $separator));
$second_part = substr($input, (strpos($input, $separator) + strlen($separator)), strlen($input));
?>
I have looked at a couple split string questions and no one suggests using the php string functions. Is there a reason for this?
list() is made for exactly this purpose.
<?php
list($artist, $title) = explode(' - ', $NowPlaying);
?>
http://php.net/manual/en/function.list.php

Ignoring apostrophes in mysql searches

I want to take a url that does not have any apostrophes, commas or ampersands in it and match it with a record in a database that may have one of those characters.
For example:
mywebsite.com/bobs-big-boy
mywebsite.com/tom--jerry
mywebsite.com/one-two-three
rewrite to
index.php?name=bobs-big-boy
index.php?name=tom--jerry
index.php?name=bobs-big-boy
Then in php I want to use the $_GET['name'] to match the records
bob's big boy
tom & jerry
one, two, three
Now my query looks like this:
"SELECT * from the_records WHERE name=$NAME";
I can't change the records, because they're business names. Is there a way I can write the query to ignore ampersands, commas and apostrophes in the db?
Yes you can but I'm pretty sure it will ignore any indexes you have on the column. And it's disgusting.
Something like
SELECT * FROM the_records
WHERE replace(replace(replace(name, '''', ''), ',', ''), '&', '') = $NAME
By the way taking a get variable like that and injecting it into the mysql query can be ripe for sql injection as far as I know.
pg, I know you said you can't change/update the content in the database you're selecting from, but does anything preclude you from making a table in another database you do have write access to? You could just make a map of urlnames to business names and it'd only be slow the first time you do the replace method.
Greetings,
This one took me a few minutes to puzzle out! There are actually a few specifics missing on you requirements, so I've tried to work through the problem with different assumptions, as stated below.
Here is the set of assumed input from the URL, as pulled from your example, along with a MySQL injection attack (just for giggles), and variations on the business names. The keys are the expected URLs and the values are the database values to match.
<?php
$names = array(
'bobs-big-boy'=>"bob's big boy",
'tom--jerry'=>'tom & jerry',
'tomjerry'=>'tom&jerry',
'one-two-three'=>'one, two, three',
'onetwothree'=>'one,two,three',
"anything' OR 'haxor'='haxor"=>'die-haxor-die',
);
?>
One clever way to do an end-run mySQL's lack of regex replacement is to use SOUNDEX, and this approach would seem to mostly work in this case depending on the level of accuracy you need, the density of and similarity of customer names, etc. For example, this generates the soundex values for the values above:
$soundex_test = $names;
$select = 'SELECT ';
foreach ($soundex_test as $name=>$dbname) {
echo '<p>'.$name.': '.soundex($name).' :: '.$dbname.': '.soundex($dbname).'</p>';
$select .= sprintf("SOUNDEX('%s'),", $name);
}
echo '<pre>MySQL queries with attack -- '.print_r($select,1).'</pre>';
So, assuming that there are not customers named 'one, two, three' and separate one named 'onetwothree', this approach should work nicely.
To use this method, your queries would look something like this:
$soundex_unclean = $names;
foreach ($soundex_unclean as $name=>$dbname) {
$soundex_unclean[$name] = sprintf("SELECT * from the_records WHERE name SOUNDS LIKE '%s';", $name).' /* matches name field = ['.$dbname.'] */';
}
echo '<pre>MySQL queries with attack -- '.print_r(array_values($soundex_unclean),1).'</pre>';
However, here is a run that DOES deal with the injection attack (note the new line). I know this isn't the focus of the question, but ajreal mentioned the issue, so I thought to deal with it as well:
$soundex_clean = $names;
foreach ($soundex_clean as $name=>$dbname) {
// strip out everything but alpha-numerics and dashes
$clean_name = preg_replace('/[^[:alnum:]-]/', '', $name);
$soundex_unclean[$name] = sprintf("SELECT * from the_records WHERE name SOUNDS LIKE '%s';", $clean_name).' /* matches name field = ['.$dbname.'] */';
}
echo '<pre>MySQL queries with attack cleaned -- '.print_r($soundex_unclean,1).'</pre>';
If this approach does not suit, and you decided that the inline replacement approach is sufficient, then do remember to add a replacement for comma to the mix as well. As an example of that approach, I'm assuming here that the single quote, double quote, ampersand, and comma (i.e. ', ", &, and ,) are the only four special characters are included in the database but deleted from the URL, and that any other non-alpha-numeric character, spaces included, are converted to a dash (i.e. -).
First, a run that does not deal with the injection attack:
$unclean = $names;
foreach ($unclean as $name=>$dbname) {
$regex_name = preg_replace('/[-]+/', '[^[:alnum:]]+', $name);
$unclean[$name] = sprintf("SELECT * from the_records WHERE REPLACE(REPLACE(REPLACE(REPLACE(name, ',', ''), '&', ''), '\"', ''), \"'\", '') REGEXP '%s'", $regex_name);
}
echo '<pre>MySQL queries with attack -- '.print_r($unclean,1).'</pre>';
Second, a run that DOES deal with the attack:
$clean = $names;
foreach ($clean as $name=>$dbname) {
$regex_name = preg_replace('/[^[:alnum:]-]/', '', $name);
$regex_name = preg_replace('/[-]+/', '[^[:alnum:]]+', $regex_name);
$clean[$name] = sprintf("SELECT * from the_records WHERE REPLACE(REPLACE(REPLACE(REPLACE(name, ',', ''), '&', ''), '\"', ''), \"'\", '') REGEXP '%s'", $regex_name);
}
echo '<pre>MySQL queries with attack cleaned -- '.print_r($clean,1).'</pre>';
Aaaand that's enough brainstorming for me for one night! =o)
Using str_replace function we will grab the $name parameter and replace
ampersands (&) with ""
spaces (" ") with "-"
commas (",") with ""
apostrophes("'") with ""
str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
$Search = { "&", " ", ",", "'" }
$Replace = { "", "-", "", "" }
$ComparableString = str_replace($Search, $Replace, $_GET['name'])
After that we can do the sql query:
$name = mysql_real_escape_string($name, $db_resource);
SELECT * from the_records WHERE name='$name'
It's a little janky, but you could explode the GET and build a WHERE on multiple conditions.
Something like (untested):
$name_array = explode("-", $_GET['name']);
$sql_str = "SELECT * FROM the_records WHERE ";
$first_time = true;
foreach($name_array as $name){
if ($name != ""){
if ($first_time){
$sql_str .= "name LIKE \"%".$name."%\"";
$first_time = false;
}
else {
$sql_str .= " AND name LIKE \"%".$name."%\"";
}
}
}

PHP: Make first letter capital in list?

As i have this:
$full_name = $data['full_name'];
list($firstname, $lastname) = explode(' ', $_POST['full_name']);
(after this comes a query where it inserts $lastname and $firstname)
Where should i use ucfirst() ?
Should i just make new variables again?
$newfirstname = ucfirst($firstname);
$newlastname = ucfirst($lastname);
or can i integrate ucfirst somehow somewhere in the code at top?
list($firstName, $lastName) = array_map('ucfirst', explode(' ', $_POST['full_name']));
array_map will apply the function to all array elements.
If they are proper names you could simply use the ucwords() function on the string.
http://www.php.net/manual/en/function.ucwords.php
I suggest using something like
$full_name = ucwords(strtolower($_POST['full_name']));
your approach
list($firstname, $lastname) = explode(' ', $_POST['full_name']);
doesn't work for names containing more than one space.

Categories