How can i unserialize a string? - php

I have a menu system that uses a drag and drop tree structure to make it easy for a user to modify. When the javascript serializes the string, it does it in the following way:
// Assume each of these items has an ID on with the respective numbers attached
Menu Item 1
+ Menu Item 2
+ Menu Item 3
+ Menu Item 4
Menu Item 5
Menu Item 6
+ Menu Item 7
This will then get serialized as:
1>2>3>>4#5#6>7
The problem with this is that there could be an arbitrary number of sublevels, which makes it difficult to unserialize. I'm using PHP server side to unserialize it but I am at a loss as to what to do.
Any suggestions welcome, even to the method of serialization, I’ll just hack the code.

You should look into json_encode/json_decode functions in PHP, those make interacting with Javascript really easy.
With your current serialization format you are just creating headaches for yourself.

I think you can split this string first by '#', then each split result splits by regex to exactly "number>number" so ">>" will not be there, then "number>>number" and so on.
Hope it helps.Sorry for my english.

If you really wanted to use that format, something like this would work, but I think JSON would be much better.
<?php
$str = '1>2>3>>4#5#6>7';
preg_match_all('~([^\d]+)?([\d]+)~', $str, $matches, PREG_SET_ORDER);
//$current is the nodes from the top to the node we are at currently
$current = array();
$result = array();
foreach ($matches as $item) {
$id = $item[2];
if (!$item[1] || $item[1] == '#') {
$level = 0;
} else {
$level = strlen($item[1]);
}
$tmp = array( 'id' => $id );
$current[ $level ] = & $tmp;
if ($level == 0) {
$result[] = & $tmp;
} elseif (isset($current[ $level - 1 ])) {
$parent = & $current[ $level - 1 ];
if (!isset($parent['children'])) {
$parent['children'] = array();
}
$parent['children'][] = & $tmp;
unset($parent);
}
unset($tmp);
}
print_r($result);

What about to serialize (instead of your string 1>2>3>>4#5#6>7) into JSON form like this:
{'1': {'2': {'3': {'4': true}}}, '5': true, '6': {'7': true}}
Then you can unserialize it using json_decode in PHP.

EDIT: for the people voting this down months after it was asked, the original format of this question DID NOT mention json or javascript. Therefore I answered in PHP, as the OP answered in the comments he corrected himself after my response, I left my answer for people getting to this page when they're searching for the PHP answer for this question even though this question isn't (now) directly answering it.
hmm...
http://php.net/manual/en/function.serialize.php
http://php.net/manual/en/function.unserialize.php
so:
$var_name = serialize( array("Menu Item 1, Menu Item 2, Menu Item 3, etc...") );
// do whatever
$var_name2 = unserialize($var_name);
Would that be a good method for you to use?

Related

Only show items with a particular criteria in an array

I am trying to show only items that meet a certain criteria in an array. At the moment I am outputting everything in the array.
What I've got so far:
$records = $d->get("FoundCount");
$result = array();
for($i = 1; $ <= $record; $i++){
// various array components
$show_published = $d->field(show_published); //this is the variable from the DB that will determine if the item is shown on the page. Yes/no string.
if($show_published == 'Yes'){
$results[] = new Result(//various array components, $show_published, //more things);
}
This seems to output all items, including the ones labeled as 'No' .
Any guidance would be great. I have only been using php for a few months now.
I'm not sure if you're familiar with composer and how to install / use php packages.
If you are, you can add illuminate/support package as a dependency for your project and use its Collection to filter records - something along the lines of:
use Illuminate\Support\Collection;
$collection = new Collection($records);
$outputArray = $collection->filter(function($object) {
return (string) $object->field('show_published') === 'Yes';
})->toArray();
https://laravel.com/docs/5.5/collections
After this, the $outputArray will contain only records that have show_published flag set to Yes.
Alternatively you could use php's native function array_filter in pretty much the same manner:
$outputArray = array_filter($records, function($object) {
return (string) $object->field('show_published') === 'Yes';
});
http://php.net/manual/en/function.array-filter.php
Here's a simple example on how to create a new filtered array based on the criteria of strings starting with the character 'b'. I'm not sure what your criteria is but you could certainly take this approach and modify it to suit your needs.
//Original array of things that are un-filtered
$oldArray = array("Baseball", "Basketball", "Bear", "Salmon", "Swordfish");
//An empty filtered array that we will populate in the loop below, based on our criteria.
$filteredArray = array();
foreach($oldArray as $arrayValue) {
//Our criteria is to only add strings to our
//filtered array that start with the letter 'B'
if($arrayValue[0] == "B")
{
array_push($filteredArray, $arrayValue);
}
}
//Our filtered array will only display
//our 3 string items that start with the character 'B'
print_r($filteredArray);
Hope it helps! If not, feel free to reach out.

Improving algorithm using MySQL

The code below is written mainly using PHP, but I am hoping to speed up the process, and parsing strings in PHP is slow.
Assume the following where I get a string from the database, and converted it into an array.
$data['options_list'] = array(
"Colours" => array('red','blue','green','purple'),
"Length" => array('3','4','5','6'),
"Voltage" => array('6v','12v','15v'),
);
These subarrays will each be a dropdown Select list, an the end user can select exactly 1 from each of the select lists.
When the user hits submit, I will want to match the submitted values against a "price table" pre-defined by the admins. Potentially "red" and "6v" would cost $5, but "red" and "5"(length) and "6v" would cost $6.
The question is, how to do so?
Currently the approach I have taken is such:
Upon submission of the form (of the 3 select lists), I get the relevant price rules set by the admin from the database. I've made an example of results.
$data['price_table'] =
array(
'red;4'=>'2',
'red;5'=>'3',
'red;6'=>'4',
'blue;3'=>'5',
'blue;4'=>'6',
'blue;5'=>'7',
'blue;6'=>'8',
'green;3'=>'9',
'green;4'=>'10',
'green;5'=>'11',
'green;6'=>'12',
'purple;3'=>'13',
'purple;4'=>'14',
'purple;5'=>'15',
'purple;6'=>'16',
'red;3'=>'1',
'red;3;12v'=>'17',
'blue;6;15v'=>'18',
);
Note : The order of the above example can be of any order, and the algorithm should work.
I then explode each of the above elements into an array, and gets the result that matches the best score.
$option_choices = $this->input->post('select');
$score = 0;
foreach($data['price_table'] as $key=>$value)
{
$temp = 0;
$keys = explode(';',$key);
foreach($keys as $k)
{
if(in_array($k, $option_choices))
{
$temp++;
}else{
$temp--;
}
}
if($temp > $score)
{
$score = $temp;
$result = $value;
}
}
echo "Result : ".$result;
Examples of expected results:
Selected options: "red","5"
Result: 3
Selected Options: "3", "red"
Result: 1
Selected Options: "red", "3", "12v"
Result: 17
The current method works as expected. However, handling these using PHP is slow. I've thought of using JSON, but that would mean that I would be giving the users my whole price table, which isn't really what I am looking for. I have also thought of using another language, (e.g python) but it wouldn't particularly be practical considering the costs. That leaves me with MySQL.
If someone can suggest a cheap and cost-efficient way to do this, please provide and example. Better still if you could provide an even better PHP solution to this which works fast.
Thank you!
It looks like you did work to make the results read faster but you're still parsing and testing every array part against the full list? This would probably run faster moving the search to MySQL and having extra columns there.
Since you can control the array (or test string) perhaps try fixed length strings:
$results = explode("\n", "
1 Red v1
22 Blue v2
333 Green v3");
$i = 0;
while($i < count($results)) {
$a = substr($results[$i], 0, 10);
$b = substr($results[$i], 10, 20);
$c = substr($results[$i], strpos(' ', strrev($results[$i]))-1);
if(stripos($userInput, $a . $b . $c) !== false) {
// parse more...
Supposedly JavaScript is good at this with memoizaion:
http://addyosmani.com/blog/faster-javascript-memoization/

fetch data from model that is called in loop

I have a controller function in CodeIgniter that looks like this:
$perm = $this->job_m->getIdByGroup();
foreach($perm as $pe=>$p)
{
$pId = $p['id'];
$result = $this->job_m->getDatapermission($pId);
}
$data['permission'] = $result;
What I need to do is list the data in the result in the view, but I get only the last value while using this method. How can I pass all the results to the view?
Store it in an array. Like this:
foreach($perm as $pe=>$p){
$result[] = $this->job_m->getDatapermission($p['id']);
}
Because $result is not an array...
try this:
$result=array();
foreach($perm as $pe=>$p)
{
$pId = $p['id'];
$result[] = $this->job_m->getDatapermission($pId);
}
$data['permission'] = $result;
Note:
My answer uses a counter to enable the display of a single group result when needed.
Guessing from your need to loop and display the value of $result, possibly, it is an array or object returned by $query->result(). Things could be a bit complex.
Example: if $perm is an array of 5 items( or groups), the counter assigns keys 1 - 5 instead of 0 - 4 as would [] which could be misleading. Using the first view example, you could choose to display a single group value if you wants by passing it via a url segment. Making the code more flexible and reusable. E.g. You want to show just returns for group 2, in my example, $result[2] would do just that else next code runs. See my comments in the code.
$perm = $this->job_m->getIdByGroup();
$counter = 1;
foreach($perm as $pe=>$p)
{
$pId = $p['id'];
$result[$counter] = $this->job_m->getDatapermission($pId);
$counter++;
}
$data['permission'] = $result;
As mentioned above Note:
I Added a Counter or Key so you target specific level. If the groups are:
Men, Women, Boys, Girls, Children; you'd know women is group two(2) If you desire to display values for just that group, you don't need to rewrite the code below. Just pass the group key would be as easy as telling it by their sequence. To display all the loop without restrictions, use the second view example. To use both, use an if statement for that.
###To access it you could target a specific level like
if(isset($permission)){
foreach($permission[2] as $key => $value){
echo $value->columnname;
}
###To get all results:
foreach($permission as $array){
foreach($array as $key => $value){
echo $value->columnname;
}
}
}

Find if an array value shows up in a string. (Kind of a reverse in_array?)

On a site I'm working on there's a subheadline that only should be shown if the information isn't already shown in the main headline. The main headline is an arbitrary string, while the subheadline is created programatically. The subheadline is generated from the contents of a multi-dimensional array (the contents of which are also used for other parts of the page.)
I used the PHP example of foreach to drill down through the array (only half-understanding how it was working), and then tried strpos to see if the values in the array were in the headline string.
Unfortunately, it doesn't work. There is a high chance that I made a stupid mistake in how I thought it's supposed to work. Or that the variable that tells the site to hide the subhead ("hider") is constantly reset to "no" as a result of the other values in the array.
foreach ($arr_info as $i1 => $n1) {
foreach ($n1 as $i2 => $n2) {
foreach ($n2 as $i3 => $n3) {
$pos = strpos($headline, $n3);
if ($pos === false) {
$hider="no";
} else {
$hider="yes";
}
}
}
Any ideas? Greatly appreciate the help.
Add this:
$hider="yes";
break;
Hope it helps
I think a cleaner approach would be to construct a regex out of the values and see if it matches your string:
$values = array();
array_walk_recursive($arr_info, function($k){$GLOBALS['values'][] = preg_quote($k);});
$hider = preg_match('/(' . implode($values, '|') . ')/', $headline) ? 'yes' : 'no';

Randomize order of <a> links on page using jQuery

I have a list of links sitting inside a tag right now. I would like for the page to 'reorganize' the order of each link on page reload (page view) and display the results.
For example:
<div id="testgroup">
1
2
3
4
5
</div>
On page reload, the soure code would look like:
<div id="testgroup">
5
1
3
4
2
</div>
or some other random order
Is there a very basic jQuery DOM manipulation script to accomplish this? If it helps, the page is built on PHP as well.
If simplicity is more important than randomness:
You can use get to convert the jQuery object to an array, then use the native sort with a function designed to randomize it. Then put the randomly arranged array back into the DOM.
var array = $("#testgroup").children().get().sort( function() {
return 0.5 - Math.random();
});
$("#testgroup").append(array);
Demo: http://jsfiddle.net/4e7cs/
If you are looking for true shuffling:
You can utilize the Fisher-Yates shuffle:
var array = $("#testgroup").children().toArray();
var i = array.length,
j, temp;
while (--i) {
j = Math.floor(Math.random() * (i + 1));
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
$("#testgroup").append(array);
Demo: http://jsfiddle.net/4e7cs/3/
Here is a writeup on why the first is bad, but I'll leave it here for completeness.
PHP has a shuffle() function to randomize arrays. You can do the randomization on the server side.
<?php
$links = array(
1 => '1.html',
2 => '2.html',
3 => '3.html',
4 => '4.html',
5 => '5.html'
);
$shuffledLinks = shuffle_assoc($links);
foreach ($shuffledLinks as $value=>$key) {
echo '<a href="'.$key.'" id='.$value.'>'.$value.'</a><br/>';
}
function shuffle_assoc($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = array();
foreach ($keys as $key)
$random[$key] = $list[$key];
return $random;
}
?>
Ok...this is now fixed and tested. Actually shuffle() did not work on associative arrays so I borrowed andjones at gmail dot com's shuffle_assoc() function for that.
I also mixed up my concatenation where I was using '+' instead of '.' O.o Mixing up my JavaScript and PHP syntax. I apologize about that.
Allen
I'm using a plugin that actualy does that : http://james.padolsey.com/javascript/sorting-elements-with-jquery/
But if you are using PHP you could sort it directly on the server?

Categories