php array_unique() returns duplicate - php

I have some code running and it's been working fine BUT the site in question has started producing a duplicate when the value in an array is "morphsuite"
The code:
if(isset($sort2))
{
$sort2 = array_unique($sort2);
foreach($sort2 as $value)
{
$f_dress .= '<li>'.$value.'</li>';
}
}
else{
$f_dress = '';
}
All the other enteries pull from the DB are OK but getting a double when the value is "morphsuit"
Anyone know why?

The values aren't exactly the same - the most likely cause is that there's some kind of non-printable embedded into one or the other (or both); things like whitespace, in-line HTML, or control characters.
Try running var_dump() on the values and pay attention to the length portion of the output when it says something like string(9) "morphsuit" vs. string(2031) "morphsuit" (I invented the number there, but you get the idea).

Related

PHP variables look the same but are not equal (I'm confused)

OK, so I shave my head, but if I had hair I wouldn't need a razor because I'd have torn it all out tonight. It's gone 3am and what looked like a simple solution at 00:30 has become far from it.
Please see the code extract below..
$psusername = substr($list[$count],16);
if ($psusername == $psu_value){
$answer = "YES";
}
else {
$answer = "NO";
}
$psusername holds the value "normann" which is taken from a URL in a text based file (url.db)
$psu_value also holds the value "normann" which is retrieved from a cookie set on the user's computer (or a parameter in the browser address bar - URL).
However, and I'm sure you can guess my problem, the variable $answer contains "NO" from the test above.
All the PHP I know I've picked up from Google searches and you guys here, so I'm no expert, which is perhaps evident.
Maybe this is a schoolboy error, but I cannot figure out what I'm doing wrong. My assumption is that the data types differ. Ultimately, I want to compare the two variables and have a TRUE result when they contain the same information (i.e normann = normann).
So if you very clever fellows can point out why two variables echo what appears to be the same information but are in fact different, it'd be a very useful lesson for me and make my users very happy.
Do they echo the same thing when you do:
echo gettype($psusername) . '\n' . gettype($psu_value);
Since i can't see what data is stored in the array $list (and the index $count), I cannot suggest a full solution to yuor problem.
But i can suggest you to insert this code right before the if statement:
var_dump($psusername);
var_dump($psu_value);
and see why the two variables are not identical.
The var_dump function will output the content stored in the variable and the type (string, integer, array ec..), so you will figure out why the if statement is returning false
Since it looks like you have non-printable characters in your string, you can strip them out before the comparison. This will remove whatever is not printable in your character set:
$psusername = preg_replace("/[[:^print:]]/", "", $psusername);
0D 0A is a new line. The first is the carriage return (CR) character and the second is the new line (NL) character. They are also known as \r and \n.
You can just trim it off using trim().
$psusername = trim($psusername);
Or if it only occurs at the end of the string then rtrim() would do the job:
$psusername = rtrim($psusername);
If you are getting the values from the file using file() then you can pass FILE_IGNORE_NEW_LINES as the second argument, and that will remove the new line:
$contents = file('url.db', FILE_IGNORE_NEW_LINES);
I just want to thank all who responded. I realised after viewing my logfile the outputs in HEX format that it was the carriage return values causing the variables to mismatch and a I mentioned was able to resolve (trim) with the following code..
$psusername = preg_replace("/[^[:alnum:]]/u", '', $psusername);
I also know that the system within which the profiles and usernames are created allow both upper and lower case values to match, so I took the precaution of building that functionality into my code as an added measure of completeness.
And I'm happy to say, the code functions perfectly now.
Once again, thanks for your responses and suggestions.

PHP, convert $_GET elements to HTML entities

Edit: I think %27 is actually the wrong kind of quote. I am still stuck though, I cannot find a PHP function that does the conversion I want.
Edit (again): I found a solution where I stick %26rsquo%3bs into the URL and it turns into ’. It works so I posted it as an answer below but I'd still be interested in knowing how it'd be done with PHP functions.
I'm working on a website that uses a PHP tree as if it were a directory. For example, if someone types index.php?foo=visual programming (or index.php?foo=visual%20programming) then the website opens the item "Visual Programming" (I'm using strtolower()).
Another working example would be index.php?foo=visual programming&bar=animated path finder which opens "Animated Path Finder", a child of "Visual Programming".
The problem is that some of the items are named things like "Conway’s Game of Life" which uses a HTML entity. My guess of what someone should type to open this would be index.php?foo=visual%20programming&bar=conway%27s%20game%20of%20life. The problem is that ' is not === to ’.
What do I need to do to make this work? Here is my code that selects an item based on $_GET (the PHP is inside of <script type="text/javascript">):
<?php
function echoActiveDirectory($inTree) {
// Compare $_GET with PhpTree
$itemId = 0;
foreach ($_GET as $name) {
if ($inTree->children !== null) {
foreach ($inTree->children as $child) {
if (strtolower($child->title) === strtolower($name)) {
$itemId = $child->id;
$inTree = $child;
break;
}
}
}
}
// Set jsItems[$itemId].selected(), it will be 0 if nothing was found
echo "\t\tjsItems[".$itemId."].selected();\n";
}
echo "// Results of PHP echoActiveDirectory(\$root)\n";
echoActiveDirectory($root);
?>
The website is a work in progress, but it can be tested here to see $_GET working: http://alexsimes.com/index.php
The hex code %27 (39 decimal) will never translate to ’, since it is a completely different entity (Wikipedia). It could be translated to &apos;, but PHP doesn't do that (although I don't know the reason for that).
Edit
While there is no standard for URL-encoding multibyte character sets, PHP will treat a string as just a set of bytes, and if those match an UTF-8 sequence, it will work:
php -r 'echo htmlentities(urldecode("%E2%80%99"), ENT_QUOTES|ENT_HTML401);'
should output
’
You can use html_entity_encode() and html_entity_decode() PHP functions to convert those characters to html entities or decode them back to desired characters before comparison.
You can try the htmlentities function to convert special characters to corresponding html entity. But in your case if data is already stored in db as html entity form, the data from $_GET parameter must be first passed through htmlentities before using it in your query.

PHP code inside MYSQL table does not show

I am trying to convert a drupal installation into a front end driven by Code Igniter. This is an experimental project to check the performance boost I can get. But the biggest problem I am facing is that few fields in Drupal store php string as it is. For example
<?php print "A"; ?>
This is normal
Now I am able to see the text "This is normal" which comes from the query that I run in Code Igniter, but I don't see the php function which is saved inside the table. I can see the text when I view the record through phpmyadmin. But somehow not inside the CI query result.
I hope U've got the solution. But just in case if you haven't try this:
I created a table with two columns
//$result Contains the data fetched from the table using a model.
foreach ($result as $key=>$val) {
if($key == 'code') {
$val = str_replace('<?php','',$val); //Remove PHP's opening tag.
$val = str_replace('?>','',$val); //Remove PHP's closing tag.
$val = rtrim($val); //Remove leading and trailing spaces.
echo $key.': ';
eval($val.';'); //Execute the PHP code using eval.
} else {
echo $key.': '.$val.PHP_EOL;
}
}
I tried
echo $result['code']
print_r($result)
var_dump($result)
highlight_string($result['code'])
eval($result['code'])
and finally str_replace followed by eval($result['code']).
Check the screen shot of the result obtained from: here
There you can see that the Result produced by 1,2, and 5 are empty. But when you inspect element against the empty space It'll clearly show that the string that's echoed/print is commented out.
Screen-Shot. This is has nothing to do with codeigniter. Its done by HTML Parser.
So the solution is to remove the opening and closing tags of PHP and then use eval. I hope this helps.
Thanks for the help. Yes, the last resort was the eval function and that is the one which helped me attain which I was wanting it to do.
The data which was inside the database had PHP function and only eval function was able to treat that part as a PHP code and execute it when I was getting the data inside my view.

Why is constructing a URL with a mysql entry in PHP giving me a different String?

I'm writing some code to look at PTO assignment data, and noticed a strange problem where the URL didn't work when I generated it from my database entry, but did work when I entered the same string manually. When I echo them both strings look the same exactly, but when I equate them they are different. Is there some kind of hidden character or something with the encoding I can't see, and if so how do I fix it? I'm running the code using WAMPSERVER.
$pto = "assignments.uspto.gov/assignments/q?db=pat&reel=";
$row = mysql_fetch_assoc($result);
$ReelFrame = $row['ReelFrame']; // Should be "007358/0006" and looks to be correct.
$reelframearray = explode("/",$ReelFrame);
$gourla = $pto . $reelframearray[0] . "&frame=". $reelframearray[1];
$gourl = "assignments.uspto.gov/assignments/q?db=pat&reel=007358&frame=0006";
echo "$gourla <br>";
echo "$gourl <br>";
if ($gourl === $gourla){
echo "same string";
} else {
echo "different";
}
This is what the results look like:
assignments.uspto.gov/assignments/q?db=pat&reel=007358&frame=0006
assignments.uspto.gov/assignments/q?db=pat&reel=007358&frame=0006
different
I've narrowed it down to the mysql entry since replacing that with this:
$ReelFrame = "007358/0006";
Makes the strings the same.
Thanks for any help. The column for ReelFrame is a VARCHAR if that makes any difference.
please try to var_dump() your both variables instead of echoing them - maybe there are some leading/trailing whitespaces, linebreaks or something like that.
EDIT: just as a note: you realy shouldn't save multiple values in one database-coumn. if ReelFrame consits of two values, make two colums out of it: Reel and Frame - and don't use charchar for this, it looks like they should be ints (and that will avoid you from saving whitespaces linebreaks or something like that accidentally)
The first thought that comes to my mind is \n character.
Try this:
$ReelFrame = trim($row['ReelFrame']);
I tried the trim() suggestion, but it doesn't seem to work. I'm not sure what kind of character it is inserting, but I guess trim isn't removing it.
I just tried the var_dump, and it does show the strings are different lengths though nothing else looks different.
vardump of a ReelFrame entity compared with manual string:
string(20) "007358/0006"
string(11) "007358/0006"
likewise for the final string:
string(81) "assignments.uspto.gov/assignments/q?db=pat&reel=007358&frame=0006"
string(72) "assignments.uspto.gov/assignments/q?db=pat&reel=007358&frame=0006"
trim() doesn't seem to make any difference on the entity so it's still showing 20.
Are there any other invisible characters that trim might miss?

PHP's preg-match_all causing Apache Segfault

I'm using two regular expressions to pull assignments out of MySQL queries and using them to create an audit trail. One of them is the 'picky' one that requires quoted column names/etc., the other one does not.
Both of them are tested and parse the values out correctly. The issue I'm having is that with certain queries the 'picky' regexp is actually just causing Apache to segfault.
I tried a variety of things to determine this was the cause up to leaving the regexp in the code, and just modifying the conditional to ensure it wasn't run (to rule out some sort of compile-time issue or something). No issues. It's only when it runs the regexp against specific queries that it segfaults, and I can't find any obvious pattern to tell me why.
The code in question:
if ($picky)
preg_match_all("/[`'\"]((?:[A-Z]|[a-z]|_|[0-9])+)[`'\"] *= *'((?:[^'\\\\]|\\\\.)*)'/", $sql, $matches);
else
preg_match_all("/[`'\"]?((?:[A-Z]|[a-z]|_|[0-9])+)[`'\"]? *= *[`'\"]?([^`'\" ,]+)[`'\"]?/", $sql, $matches);
The only difference between the two is that the first one removes the question marks on the quotes to make them non-optional and removes the option of using different kinds of quotes on the value - only allows single quotes. Replacing the first regexp with the second (for testing purposes) and using the same data removes the issue - it is definitely something to do with the regexp.
The specific SQL that is causing me grief is available at:
http://stackoverflow.pastebin.com/m75c2a2a0
Interestingly enough, when I remove the highlighted section, it all works fine. Trying to submit the highlighted section by itself causes no error.
I'm pretty perplexed as to what's going on here. Can anyone offer any suggestions as to further debugging or a fix?
EDIT: Nothing terribly exciting, but for the sake of completeness here's the relevant log entry from Apache (/var/log/apache2/error.log - There's nothing in the site's error.log. Not even a mention of the request in the access log.)
[Thu Dec 10 10:08:03 2009] [notice] child pid 20835 exit signal Segmentation fault (11)
One of these for each request containing that query.
EDIT2: On the suggestion of Kuroki Kaze, I tried gibberish of the same length and got the same segfault. Sat and tried a bunch of different lengths and found the limit. 6035 characters works fine. 6036 segfaults.
EDIT3: Changing the values of pcre.backtrack_limit and pcre.recursion_limit in php.ini mitigated the problem somewhat. Apache no longer segfaults, but my regexp no longer matches all of the matches in the string. Apparently this is a long-known (from 2007) bug in PHP/PCRE:
http://bugs.php.net/bug.php?id=40909
EDIT4: I posted the code in the answers below that I used to replace this specific regular expression as the workarounds weren't acceptable for my purpose (product for sale, can't guarantee php.ini changes and the regexp only partially working removed functionality we require). Code I posted is released into the public domain with no warranty or support of any kind. I hope it can help someone else. :)
Thank you everyone for the help!
Adam
I have been hit with a similar preg_match-related issue, same Apache segfault. Only the preg_match that causes it is built-into the CMS I'm using (WordPress).
The "workaround" that was offered was to change these settings in php.ini:
[Pcre]
;PCRE library backtracking limit.
;pcre.backtrack_limit=100000
pcre.recursion_limit=200000000
pcre.backtrack_limit=100000000
The trade-off is for rendering larger pages, (in my case, > 200 rows; when one of the columns is limited to a 1500-character text description), you'll get pretty high CPU utilization, and I'm still seeing the segfaults. Just not as frequently.
My site's close to end-of-life, so I don't really have much need (or budget) to look for a real solution. But maybe this can mitigate the issue you're seeing.
Interestingly enough, when I remove the highlighted section, it all works fine. Trying to submit the highlighted section by itself causes no error.
What about size of the submission? If you pass gibberish of equal length, what will happen?
EDIT: splitting and merging will look something like this:
$strings = explode("\n", $sql);
$matches = array(array(), array(), array());
foreach ($strings AS $string) {
preg_match_all("/[`'\"]?((?:[A-Z]|[a-z]|_|[0-9])+)[`'\"]? *= *[`'\"]?([^`'\" ,]+)[`'\"]?/", $string, $matches_temp);
$matches[0] = array_merge($matches[0], $matches_temp[0]);
$matches[1] = array_merge($matches[1], $matches_temp[1]);
$matches[2] = array_merge($matches[2], $matches_temp[2]);
}
Given that this only needs to match against the queries when saving pages or performing other not very often-executed operations, I felt the performance hit of the following code was acceptable. It parses the SQL query ($sql) and places name=>value pairs into $data. Seems to be working well and handles large queries fine.
$quoted = '';
$escaped = false;
$key = '';
$value = '';
$target = 'key';
for ($i=0; $i<strlen($sql); $i++)
{
if ($escaped)
{
$$target .= $sql[$i];
$escaped = false;
}
else if ($quoted!='')
{
if ($sql[$i]=='\\')
$escaped = true;
else if ($sql[$i]==$quoted)
$quoted = '';
else
$$target .= $sql[$i];
}
else
{
if ($sql[$i]=='\'' || $sql[$i]=='`')
{
$quoted = $sql[$i];
$$target = '';
}
else if ($sql[$i]=='=')
$target = 'value';
else if ($sql[$i]==',')
{
$target = 'key';
$data[$key] = $value;
$key = '';
$value = '';
}
}
}
if ($value!='')
$data[$key] = $value;
Thank you everyone for the help and direction!

Categories