I am in the middle of building a cache layer for the Redis DB to my application and I have come to the point where's it's about to take care of arrays.
I wonder if there's any good (high performance!) way of controlling an string to be serialized or not with PHP?
Thanks a lot!
$array = #unserialize($string);
if ($array === false && $string !== 'b:0;') {
// woops, that didn't appear to be anything serialized
}
The $string !== 'b:0;' checks to see if the serialized string may have been the value false. If this check is important to you you may want to trim the serialized string or otherwise preprocess it to make sure this works.
For those looking for alternative, this code worked for me as helper function for Laravel framework and then you can call it anywhere.
if(!function_exists('isSerialized')){
function isSerialized($string){
$tempString = '';
$array = #unserialize($string);
if(is_array($array)){
foreach ($array as $k=>$i){
//do something with data
$tempString .= $k . $i['something'];
}
} else {
$tempString = $string;
}
return $itemString;
}
}
Related
How can I unserialize data in jQuery? remember data is Serialized by PHP. Below is given example.
a:2:{i:0;s:9:" img1.jpeg";i:1;s:9:"img2.jpeg";}
This can be achieved using unserialize and json_encode
$unserialized = unserialize($serialized_from_db);
echo json_encode($unserialized);
But please note your sample provided: s:9:" img1.jpeg" this part is incorrect. The s:9 means it expects string to be 9 bytes (this link provides a good guide on understanding output from serialize), however " img1.jpeg has a space and therefore is 10 bytes and fails: demo failing. You can add a check to see if this failes to unserialize:
if ($unserialized === false)
When you fix the incorrect part to: s:9:"img1.jpeg, giving you:
a:2:{i:0;s:9:"img1.jpeg";i:1;s:9:"img2.jpeg";}
will now work, see demo.
At the end of the day I would recommend as others have above, to store json_encoded values in your database rather than serialized values.
I came up with a really hacky hack to potentially fix bad serialized data:
<?php
function hackFixUnserialized($unserialized_string) {
$parts = explode(';', $unserialized_string);
foreach ($parts as &$part) {
$kv = explode(':', $part);
if ($kv[0] == 's') {
$str_without_quotes = str_replace('"', '', $kv[2]);
if ($kv[1] != strlen($str_without_quotes)) {
$kv[1] = strlen($str_without_quotes);
}
}
$part = implode(':', $kv);
}
return implode(';', $parts);
}
$unserialized_from_db = <<<EOT
a:2:{i:0;s:9:" img1.jpeg";i:1;s:9:"img2.jpeg";}
EOT;
$unserialized = unserialize($unserialized_from_db);
if ($unserialized === false) {
$hack_fix = hackFixUnserialized($unserialized_from_db);
printf('bad unserialized, fixed to: %s%s', $hack_fix, PHP_EOL);
$unserialized = unserialize($hack_fix);
}
echo json_encode($unserialized);
Demo of it here: https://eval.in/783408
Hope this helps
TL;DR
I have this data: var_export and print_r.
And I need to narrow it down to: http://pastebin.com/EqwgpgAP ($data['Stock Information:'][0][0]);
How would one achieve it? (dynamically)
I'm working with vTiger 5.4.0 CRM and am looking to implement a function that would return a particular field information based on search criteria.
Well, vTiger is pretty weakly written system, looks and feels old, everything comes out from hundreds of tables with multiple joins (that's actually not that bad) etc., but job is job.
The need arose from getting usageunit picklist from Products module, Stock Information block.
Since there is no such function as getField();, I am looking forward to filter it out from Blocks, that is actually gathering the information about fields also.
getBlocks(); then calls something close to getFields();, that again something close to getValues(); and so on.
So...
$focus = new $currentModule(); // Products
$displayView = getView($focus->mode);
$productsBlocks = getBlocks($currentModule, $displayView, $focus->mode, $focus->column_fields); // in theory, $focus->column_fields should/could be narrowed down to my specific field, but vTiger doesn't work that way
echo "<pre>"; print_r($productsBlocks); echo "</pre>"; // = http://pastebin.com/3iTDUUgw (huge dump)
As you can see, the array under the key [Stock Information:], that actually comes out from translations (yada, yada...), under [0][0] contains information for usageunit.
Now, I was trying to array_filter(); the data out from there, but only thing I've managed to get is $productsBlocks stripped down to only contain [Stock Information:] with all the data:
$getUsageUnit = function($value) use (&$getUsageUnit) {
if(is_array($value)) return array_filter($value, $getUsageUnit);
if($value == 'usageunit') return true;
};
$productsUsageUnit = array_filter($productsBlocks, $getUsageUnit);
echo "<pre>"; print_r($productsUsageUnit); echo "</pre>"; // = http://pastebin.com/LU6VRC4h (not that huge of a dump)
And, the result I'm looking forward to is http://pastebin.com/EqwgpgAP, that I've manually got by print_r($productsUsageUnit['Stock Information:'][0][0]);.
How do I achieve this? (dynamically...)
function helper($data, $query) {
$result = array();
$search = function ($data, &$stack) use(&$search, $query) {
foreach ($data as $entry) {
if (is_array($entry) && $search($entry, $stack) || $entry === $query) {
$stack[] = $entry;
return true;
}
}
return false;
};
foreach ($data as $sub) {
$parentStack = array();
if ($search($sub, $parentStack)) {
$result[] = $parentStack[sizeof($parentStack) - 2];
}
}
return $result;
}
$node = helper($data, 'usageunit');
print_r($node);
Does anyone know why this doesn't work
function my_current($array) {
return current($array);
}
$array = array(1,3,5,7,13);
while($i = my_current($array)) {
$content .= $i.',';
next($array);
}
yet this does
$array = array(1,3,5,7,13);
while($i = current($array)) {
$content .= $i.',';
next($array);
}
or how to make the top one work?
It's a little question but it would be a big help!
Thanks
Richard
The array is copied, which means that the current pointer is lost. Pass it as a reference.
function my_current(&$array) {
Or better yet, use implode().
By default a copy of the array is being made.
Try this:
function my_current(&$array) {
return current($array);
}
I guess it's because when you call a function with an array parameter, the array is copied over. Try using references.
function my_current(&$array) {
return current($array);
}
Notice the &.
Hello I know all about http://www.php.net/manual/en/function.http-build-query.php to do this however I have a little problem.
It "handly" turns boolean values into ones and zeros for me. I am building a little PHP wrapper for the Stack Overflow api and parsing an option array and then sending this onto the api breaks things..(doesn't like 1 for true).
What I would like is a simple function to turn a single dimensional array into a query string but turning true/false into string values of true/false.
Anyone know of anything that can do this before I start re-inventing the wheel
I don't know of anything offhand. What I'd recommend is first iterating through the array and covert booleans to strings, then call http_build_query
E.g.
foreach($options_array as $key=>$value) :
if(is_bool($value) ){
$options_array[$key] = ($value) ? 'true' : 'false';
}
endforeach;
$options_string=http_build_query($options_array);
Try passing http_build_query true and false as strings instead of booleans. You may get different results.
If you just need to convert your true/false to "true"/"false":
function aw_tostring (&$value,&$key) {
if ($value === true) {
$value = 'true';
}
else if ($value === false) {
$value = 'false';
}
}
array_walk($http_query,'aw_tostring');
// ... follow with your http_build_query() call
Loop through each variable of the query string ($qs) and if bool true or false, then change value to string.
foreach($qs as $key=>$q) {
if($q === true) $qs[$key] = 'true';
elseif($q === false) $qs[$key] = 'false';
}
Then you can use the http_build_query()
have a look at my wheel:
function buildSoQuery(array $array) {
$parts = array();
foreach ($array as $key => $value) {
$parts[] = urlencode($key).'='.(is_bool($value)?($value?'true':'false'):urlencode($value));
}
return implode('&', $parts);
}
I have a query string like the one given below:
http://localhost/project/viewMember.php?sort=Y2xhc3M=&class=Mw==&page=9
Now variable: page in query string can be anywhere within the query string either in beginning or middle or at end (like ?page=9 or &page=9& or &page=9).
Now, I need to remove page=9 from my query string and get a valid query string.
Lots of ways this could be done, including regex (as seen below). This is the most robust method I can think of, although it is more complex than the other methods.
Use parse_url to get the query string from the url (or write your own function).
Use parse_str to convert the query string into an array
unset the key that you don't want
Use http_build_query to reassemble the array into a query string
Then reconstruct the Url (if required)
Try:
preg_replace('/page=\d+/', '', $url);
Tried writing a function for this. Seems to work:
<?php
$url = "http://localhost/project/viewMember.php?sort=Y2xhc3M=&class=Mw==&page=9";
// prints http://localhost/project/viewMember.php?sort=Y2xhc3M=&class=Mw==
print changeURL($url) . "\n";
$url = "http://localhost/project/viewMember.php?sort=Y2xhc3M=&page=9&class=Mw==";
// prints http://localhost/project/viewMember.php?sort=Y2xhc3M=&class=Mw==
print changeURL($url) . "\n";
function changeURL($url)
{
$arr = parse_url($url);
$query = $arr['query'];
$pieces = explode('&',$query);
for($i=0;$i<count($pieces);$i++)
{
if(preg_match('/^page=\d+/',$pieces[$i]))
unset($pieces[$i]);
}
$query = implode('&',$pieces);
return "$arr[scheme]://$arr[host]$arr[user]$arr[pass]$arr[path]?$query$arr[fragment]";
}
?>
I created these two functions:
function cleanQuery($queryLabels){
// Filter all items in $_GET which are not in $queryLabels
if(!is_array($queryLabels)) return;
foreach($_GET as $queryLabel => $queryValue)
if(!in_array($queryLabel, $queryLabels) || ($queryValue == ''))
unset($_GET[$queryLabel]);
ksort($_GET);
}
function amendQuery($queryItems = array()){
$queryItems = array_merge($_GET, $queryItems);
ksort($queryItems);
return http_build_query($queryItems);
}
To remove the page part I would use
$_GET = amendQuery(array('page'=>null));
cleanQuery does the opposite. Pass in an array of the terms you want to keep.
function remove_part_of_qs($removeMe)
{
$qs = array();
foreach($_GET as $key => $value)
{
if($key != $removeMe)
{
$qs[$key] = $value;
}
}
return "?" . http_build_query($qs);
}
echo remove_part_of_qs("page");
This should do it, this is my first post on StackOverflow, so go easy!