Parse string containing dots in php - php

I would parse the following string:
$str = 'ProceduresCustomer.tipi_id=10&ProceduresCustomer.id=1';
parse_str($str,$f);
I wish that $f be parsed into:
array(
'ProceduresCustomer.tipi_id' => '10',
'ProceduresCustomer.id' => '1'
)
Actually, the parse_str returns
array(
'ProceduresCustomer_tipi_id' => '10',
'ProceduresCustomer_id' => '1'
)
Beside writing my own function, does anybody know if there is a php function for that?

From the PHP Manual:
Dots and spaces in variable names are converted to underscores. For example <input name="a.b" /> becomes $_REQUEST["a_b"].
So, it is not possible. parse_str() will convert all periods to underscores. If you really can't avoid using periods in your query variable names, you will have to write custom function to achieve this.
The following function (taken from this answer) converts the names of each key-value pair in the query string to their corresponding hexadecimal form and then does a parse_str() on it. Then, they're reverted back to their original form. This way, the periods aren't touched:
function parse_qs($data)
{
$data = preg_replace_callback('/(?:^|(?<=&))[^=[]+/', function($match) {
return bin2hex(urldecode($match[0]));
}, $data);
parse_str($data, $values);
return array_combine(array_map('hex2bin', array_keys($values)), $values);
}
Example usage:
$data = parse_qs($_SERVER['QUERY_STRING']);

Quick 'n' dirty.
$str = "ProceduresCustomer.tipi_id=10&ProceduresCustomer.id=1";
function my_func($str){
$expl = explode("&", $str);
foreach($expl as $r){
$tmp = explode("=", $r);
$out[$tmp[0]] = $tmp[1];
}
return $out;
}
var_dump(my_func($str));
array(2) {
["ProceduresCustomer.tipi_id"]=> string(2) "10"
["ProceduresCustomer.id"]=>string(1) "1"
}

This quick-made function attempts to properly parse the query string and returns an array.
The second (optional) parameter $break_dots tells the parser to create a sub-array when encountering a dot (this goes beyond the question, but I included it anyway).
/**
* parse_name -- Parses a string and returns an array of the key path
* if the string is malformed, only return the original string as a key
*
* $str The string to parse
* $break_dot Whether or not to break on dots (default: false)
*
* Examples :
* + parse_name("var[hello][world]") = array("var", "hello", "world")
* + parse_name("var[hello[world]]") = array("var[hello[world]]") // Malformed
* + parse_name("var.hello.world", true) = array("var", "hello", "world")
* + parse_name("var.hello.world") = array("var.hello.world")
* + parse_name("var[hello][world") = array("var[hello][world") // Malformed
*/
function parse_name ($str, $break_dot = false) {
// Output array
$out = array();
// Name buffer
$buf = '';
// Array counter
$acount = 0;
// Whether or not was a closing bracket, in order to avoid empty indexes
$lastbroke = false;
// Loop on chars
foreach (str_split($str) as $c) {
switch ($c) {
// Encountering '[' flushes the buffer to $out and increments the
// array counter
case '[':
if ($acount == 0) {
if (!$lastbroke) $out[] = $buf;
$buf = "";
$acount++;
$lastbroke = false;
// In this case, the name is malformed. Return it as-is
} else return array($str);
break;
// Encountering ']' flushes rge buffer to $out and decrements the
// array counter
case ']':
if ($acount == 1) {
if (!$lastbroke) $out[] = $buf;
$buf = '';
$acount--;
$lastbroke = true;
// In this case, the name is malformed. Return it as-is
} else return array($str);
break;
// If $break_dot is set to true, flush the buffer to $out.
// Otherwise, treat it as a normal char.
case '.':
if ($break_dot) {
if (!$lastbroke) $out[] = $buf;
$buf = '';
$lastbroke = false;
break;
}
// Add every other char to the buffer
default:
$buf .= $c;
$lastbroke = false;
}
}
// If the counter isn't back to 0 then the string is malformed. Return it as-is
if ($acount > 0) return array($str);
// Otherwise, flush the buffer to $out and return it.
if (!$lastbroke) $out[] = $buf;
return $out;
}
/**
* decode_qstr -- Take a query string and decode it to an array
*
* $str The query string
* $break_dot Whether or not to break field names on dots (default: false)
*/
function decode_qstr ($str, $break_dots = false) {
$out = array();
// '&' is the field separator
$a = explode('&', $str);
// For each field=value pair:
foreach ($a as $param) {
// Break on the first equal sign.
$param = explode('=', $param, 2);
// Parse the field name
$key = parse_name($param[0], $break_dots);
// This piece of code creates the array structure according to th
// decomposition given by parse_name()
$array = &$out; // Reference to the last object. Starts to $out
$append = false; // If an empty key is given, treat it like $array[] = 'value'
foreach ($key as $k) {
// If the current ref isn't an array, make it one
if (!is_array($array)) $array = array();
// If the current key is empty, break the loop and append to current ref
if (empty($k)) {
$append = true;
break;
}
// If the key isn't set, set it :)
if (!isset($array[$k])) $array[$k] = NULL;
// In order to walk down the array, we need to first save the ref in
// $array to $tmp
$tmp = &$array;
// Deletes the ref from $array
unset($array);
// Create a new ref to the next item
$array =& $tmp[$k];
// Delete the save
unset($tmp);
}
// If instructed to append, do that
if ($append) $array[] = $param[1];
// Otherwise, just set the value
else $array = $param[1];
// Destroy the ref for good
unset($array);
}
// Return the result
return $out;
}
I tried to correctly handle multi-level keys. The code is a bit hacky, but it should work. I tried to comment the code, comment if you have any question.
Test case:
var_dump(decode_qstr("ProceduresCustomer.tipi_id=10&ProceduresCustomer.id=1"));
// array(2) {
// ["ProceduresCustomer.tipi_id"]=>
// string(2) "10"
// ["ProceduresCustomer.id"]=>
// string(1) "1"
// }
var_dump(decode_qstr("ProceduresCustomer.tipi_id=10&ProceduresCustomer.id=1", true));
// array(1) {
// ["ProceduresCustomer"]=>
// array(2) {
// ["tipi_id"]=>
// string(2) "10"
// ["id"]=>
// string(1) "1"
// }
// }

I would like to add my solution as well, because I had trouble finding one that did all I needed and would handle all circumstances. I tested it quite thoroughly. It keeps dots and spaces and unmatched square brackets (normally changed to underscores), plus it handles arrays in the input well. Tested in PHP 8.0.0 and 8.0.14.
const periodPlaceholder = 'QQleQPunT';
const spacePlaceholder = 'QQleQSpaTIE';
function parse_str_clean($querystr): array {
// without the converting of spaces and dots etc to underscores.
$qquerystr = str_ireplace(['.','%2E','+',' ','%20'], [periodPlaceholder,periodPlaceholder,spacePlaceholder,spacePlaceholder,spacePlaceholder], $querystr);
$arr = null ; parse_str($qquerystr, $arr);
sanitizeArr($arr, $querystr);
return $arr;
}
function sanitizeArr(&$arr, $querystr) {
foreach($arr as $key=>$val) {
// restore values to original
if ( is_string($val)) {
$newval = str_replace([periodPlaceholder,spacePlaceholder], ["."," "], $val);
if ( $val != $newval) $arr[$key]=$newval;
}
}
unset($val);
foreach($arr as $key=>$val) {
$newkey = str_replace([periodPlaceholder,spacePlaceholder], ["."," "], $key);
if ( str_contains($newkey, '_') ) {
// periode of space or [ or ] converted to _. Restore with querystring
$regex = '/&('.str_replace('_', '[ \.\[\]]', preg_quote($newkey, '/')).')=/';
$matches = null ;
if ( preg_match_all($regex, "&".urldecode($querystr), $matches) ) {
if ( count(array_unique($matches[1])) === 1 && $key != $matches[1][0] ) {
$newkey = $matches[1][0] ;
}
}
}
if ( $newkey != $key ) $arr = array_replace_key($arr,$key, $newkey);
if ( is_array($val)) {
sanitizeArr($arr[$newkey], $querystr);
}
}
}
function array_replace_key($array, $oldKey, $newKey): array {
// preserves order of the array
if( ! array_key_exists( $oldKey, $array ) ) return $array;
$keys = array_keys( $array );
$keys[ array_search( $oldKey, $keys ) ] = $newKey;
return array_combine( $keys, $array );
}
First replaces spaces and . by placeholders in querystring before coding before parsing, later undoes that within the array keys and values. This way we can use the normal parse_str.
Unmatched [ and ] are also replaced by underscores by parse_str, but these cannot be reliably replaced by a placeholder. And we definitely don't want to replace matched []. Hence we don't replace [ and ], en let them be replaced by underscores by parse_str. Then we restore the _ in the resulting keys and seeing in the original querystring if there was a [ or ] there.
Known bug: keys 'something]something' and almost identical 'something[something' may be confused. It's occurrence will be zero, so I left it.
Test:
var_dump(parse_str_clean("code.1=printr%28hahaha&code 1=448044&test.mijn%5B%5D%5B2%5D=test%20Roemer&test%20mijn%5B=test%202e%20Roemer"));
yields correctly
array(4) {
["code.1"]=>
string(13) "printr(hahaha"
["code 1"]=>
string(6) "448044"
["test.mijn"]=>
array(1) {
[0]=>
array(1) {
[2]=>
string(11) "test Roemer"
}
}
["test[mijn"]=>
string(14) "test 2e Roemer"
}
whereas the original parse_str only yields, with the same string:
array(2) {
["code_1"]=>
string(6) "448044"
["test_mijn"]=>
string(14) "test 2e Roemer"
}

Related

Convert CSV to JSON using PHP

I am trying to convert CSV file to JSON using PHP.
Here is my code
<?php
date_default_timezone_set('UTC');
$today = date("n_j"); // Today is 1/23/2015 -> $today = 1_23
$file_name = $today.'.CSV'; // My file name is 1_23.csv
$file_path = 'C:\\Users\\bheng\\Desktop\\qb\\'.$file_name;
$file_handle = fopen($file_path, "r");
$result = array();
if ($file_handle !== FALSE) {
$column_headers = fgetcsv($file_handle);
foreach($column_headers as $header) {
$result[$header] = array();
}
while (($data = fgetcsv($file_handle)) !== FALSE) {
$i = 0;
foreach($result as &$column) {
$column[] = $data[$i++];
}
}
fclose($file_handle);
}
// print_r($result); // I see all data(s) except the header
$json = json_encode($result);
echo $json;
?>
print_r($result); // I see all data(s)
Then I json_encode($result); and tried to display it, but nothing is displaying on the screen at all. All I see is the blank screen, and 0 error message.
Am I doing anything wrong ? Can someone help me ?
Added Result of print_r($result);
Array (
[Inventory] => Array (
[0] => bs-0468R(20ug)
[1] => bs-1338R(1ml)
[2] => bs-1557G(no bsa)
[3] => bs-3295R(no BSA)
[4] => bs-0730R-Cy5"
[5] => bs-3889R-PE-Cy7"
[6] => 11033R
[7] => 1554R-A647
[8] => 4667
[9] => ABIN731018
[10] => Anti-DBNL protein
.... more ....
Try like this:
$file="1_23.csv";
$csv= file_get_contents($file);
$array = array_map("str_getcsv", explode("\n", $csv));
$json = json_encode($array);
print_r($json);
data.csv
Game,Skill
Treasure Hunter,pilipala
Rocket Launcher,bibobibo
Rocket Engine,hehehohoho
To convert with column name, this is how I do it.
csv2json.php
<?php
if (($handle = fopen("data.csv", "r")) !== FALSE) {
$csvs = [];
while(! feof($handle)) {
$csvs[] = fgetcsv($handle);
}
$datas = [];
$column_names = [];
foreach ($csvs[0] as $single_csv) {
$column_names[] = $single_csv;
}
foreach ($csvs as $key => $csv) {
if ($key === 0) {
continue;
}
foreach ($column_names as $column_key => $column_name) {
$datas[$key-1][$column_name] = $csv[$column_key];
}
}
$json = json_encode($datas);
fclose($handle);
print_r($json);
}
The output result
[
{
"Game": "Treasure Hunter",
"Skill": "pilipala"
},
{
"Game": "Rocket Launcher",
"Skill": "bibobibo"
},
{
"Game": "Rocket Engine",
"Skill": "hehehohoho"
}
]
You can try this way too.
<?php
function csvtojson($file,$delimiter)
{
if (($handle = fopen($file, "r")) === false)
{
die("can't open the file.");
}
$csv_headers = fgetcsv($handle, 4000, $delimiter);
$csv_json = array();
while ($row = fgetcsv($handle, 4000, $delimiter))
{
$csv_json[] = array_combine($csv_headers, $row);
}
fclose($handle);
return json_encode($csv_json);
}
$jsonresult = csvtojson("./doc.csv", ",");
echo $jsonresult;
I ran into a similar problem, I ended up using this to recursively convert the data to UTF-8 on an array before encoding to JSON.
function utf8_converter($array)
{
array_walk_recursive($array, function(&$item, $key){
if(!mb_detect_encoding($item, 'utf-8', true)){
$item = utf8_encode($item);
}
});
return $array;
}
From:
http://nazcalabs.com/blog/convert-php-array-to-utf8-recursively/
This issue is pretty old by now, but hoping this helps someone, as it seemed like the simplest example I found, and I know this is a pretty common thing devs might need to do as a beginner, and lots of answers gloss over the magic.
$file = storage_path('app/public/waitlist_users_test.csv'); //--> laravel helper, but you can use any path here
function csv_to_json($file)
{
// file() loads each row as an array value, then array map uses the 'str_getcsv' callback to
$csv = array_map('str_getcsv', file($file));
// array_walk - "walks" through each item of the array and applies the call back function. the & in "&row" means that alterations to $row actually change the original $csv array, rather than treating it as immutable (*sort of immutable...)
array_walk($csv, function(&$row) use ($csv) {
// array_combine takes the header row ($csv[0]) and uses it as array keys for each column in the row
$row = array_combine($csv[0], $row);
});
array_shift($csv); # removes now very redundant column header --> contains {'col_1':'col_1', 'col_2':'col_2'...}
$json = json_encode($csv);
return $json;
}
There's a lot of magic going on with these functions that accept callback functions, that didn't seem to be explained thoroughly above. I'm self taught and have been programming for years, and find that it's often just glossed over without detailing how callbacks work, so I'll dive in just a little bit for the array_map('str_getcsv', file($file)) function - if you pass a function you've written, or inbuilt php function name as a string, it will take the value of whatever (in this case - array) element is being evaluated by the calling function (in this case array_map), and pass that to the callback function without the need to explicitly pass in a variable - super helpful once you get the hang of it, but I find it's not explained thoroughly very often which leaves beginners to not understand why it works, just that it works.
I've linked most of these above, but here's a little more information:
str-getcsv do? Array Walk Array Map Callables/Callbacks
as #MoonCactus noted, the file() function only loads 1 row at a time which helps save on memory usage for large .csv files.
Also, some other posts reference using explode - why not use explode() instead of str_getcsv() to parse rows? Because explode() would not treat possible enclosured parts of string or escaped characters correctly.
Hope somebody finds this helpful!
If you are converting a dynamic CSV file, you can pass the URL through a parameter (url=http://example.com/some.csv) and it will show you the most up-to-date version:
<?php
// Lets the browser and tools such as Postman know it's JSON
header( "Content-Type: application/json" );
// Get CSV source through the 'url' parameter
if ( isset( $_GET['url'] ) ) {
$csv = explode( "\n", file_get_contents( $_GET['url'] ) );
$index = str_getcsv( array_shift( $csv ) );
$json = array_map(
function ( $e ) use ( $index ) {
return array_combine( $index, str_getcsv( $e ) );
}, $csv
);
}
else {
$json = "Please set the path to your CSV by using the '?url=' query string.";
}
// Output JSON
echo json_encode( $json );
Alternate solution that uses similar method as #Whirlwind's solution but returns a more standard JSON result (with named fields for each object/record):
// takes a string of CSV data and returns a JSON representing an array of objects (one object per row)
function convert_csv_to_json($csv_data){
$flat_array = array_map("str_getcsv", explode("\n", $csv_data));
// take the first array item to use for the final object's property labels
$columns = $flat_array[0];
for ($i=1; $i<count($flat_array)-1; $i++){
foreach ($columns as $column_index => $column){
$obj[$i]->$column = $flat_array[$i][$column_index];
}
}
$json = json_encode($obj);
return $json; // or just return $obj if that's a more useful return value
}
The accepted answer uses file_get_contents() to read the entire file as a string in memory, and then explode() it to make it an array.
But it can be made faster, smaller in memory, and more useful:
function ReadCsv($fn)
{
$lines= file($fn); // read file directly as an array of lines
array_pop($lines); // you can remove the last empty line (if required)
$json= json_encode(array_map("str_getcsv", $lines), JSON_NUMERIC_CHECK);
print_r($json);
}
Nb: I used JSON_NUMERIC_CHECK here to avoid numbers being double quoted into strings. It also reduces the output size and it usually helps javascript on the other side (e.g. to compute or plot the data). Beware of phone numbers though!
I liked #ian-d-miller's solution for converting the data into a key / value style format, but I kept running into issues with his code.
Here's what worked for me:
function convert_CSV_to_JSON($csv_data){
// convert csv data to an array
$data = array_map("str_getcsv", explode("\n", $csv_data));
// use the first row as column headers
$columns = $data[0];
// create array to hold our converted data
$json = [];
// iterate through each row in the data
foreach ($data as $row_index => $row_data) {
// skip the first row, since it's the headers
if($row_index === 0) continue;
// make sure we establish each new row as an array
$json[$row_index] = [];
// iterate through each column in the row
foreach ($row_data as $column_index => $column_value) {
// get the key for each entry
$label = $columns[$column_index];
// add this column's value to this row's index / column's key
$json[$row_index][$label] = $column_value;
}
}
// bam
return $json;
}
Usage:
// as is
$json = convert_CSV_to_JSON($csv);
// encoded
$json = json_encode($json);
Something that i've made for myself and may be useful for others :)
This will convert CSV into JSON array with objects (key => value pair).
function csv2json($a, $e = true) {
$b = ["\r\n","\r","\n",];
foreach ($b as $c => $d) {
$a = explode($d, $a);
$a = isset($b[$c + 1]) ? implode($b[$c + 1], $a) : implode(PHP_EOL, $a);
}
// Convert to CSV
$a = array_map("str_getcsv", explode(PHP_EOL, $a));
// Get the first part of the array as the keys
$a = [
"keys" => array_shift($a),
"rows" => $a,
"row" => null,
];
// Define JSON
$b = [];
foreach ($a["rows"] as $a["row"]) {
$a["row"] = [ "csv" => $a["row"], "json" => (object)[], ];
for ($c = 0; $c < count($a["row"]["csv"]); $c++) {
$a["row"]["csv"][$c] = [#json_decode($a["row"]["csv"][$c]),$a["row"]["csv"][$c]];
// Switch from string to booleans, numbers and others
$a["row"]["csv"][$c] = isset($a["row"]["csv"][$c][0]) ? $a["row"]["csv"][$c][0] : $a["row"]["csv"][$c][1];
// Push it back
$a["row"]["json"]->{$a["keys"][$c]} = $a["row"]["csv"][$c];
}
$a["row"] = $a["row"]["json"];
$b[] = $a["row"];
unset($a["row"]);
}
// $e will be "return"
$e = $e ? json_encode($b) : $b;
// Unset useless variables
unset($a, $b, $c, $d);
return $e;
}
How to use?
If you want to return the JSON as a string, Leave it as default.
If you want to return the JSON as an object / array, set the second parameter to false.
Examples:
$csv = "name,age,gender
John Doe,35,male
Jane Doe,32,female";
echo csv2json($csv, true); // Or without the second parameter, just csv2json($csv)
The example above (^) will return a JSON stringified, Like this:
[{"name":"John Doe","age":35,"gender":"male"},{"name":"Jane Doe","age":32,"gender":"female"}]
and the example below:
var_dump(csv2json($csv, false));
will return a JSON array with these objects:
array(2) {
[0]=>
object(stdClass)#1 (3) {
["name"]=>
string(8) "John Doe"
["age"]=>
int(35)
["gender"]=>
string(4) "male"
}
[1]=>
object(stdClass)#2 (3) {
["name"]=>
string(8) "Jane Doe"
["age"]=>
int(32)
["gender"]=>
string(6) "female"
}
}
public function CsvToJson($fileContent){
//Convert CSV To Json and Return
$all_rows = array();
$newhead =array();
//Extract csv data to array on \n
$array = explode("\n",$fileContent);
//Extract csv header to array on 0 Index
$header = explode(",",$array[0]);
//Remove Header Row From Main Data Array
array_shift($array);
//Extract All Arrays To Saperate Orders
foreach($array as $arr){
$sliced = explode(",",$arr);
array_push($all_rows,$sliced);
}
//Extract All Orders Element To Saperate Array Item
foreach($all_rows as $row){
$sliced = explode(",",$arr);
array_push($all_rows,$sliced);
}
//Remove \r From Header Elements
foreach($header as $key=>$value){
$sliced = str_replace ("\r", "", $value);
array_push($newhead,$sliced);
}
//COMBINE Header as KEY And Row Element As Value
$arrrr = array();
foreach($all_rows as $row) {
//Remove Last Element of ROW if it is \r (Break given in css file for next row)
$count= count($row);
if ($row[$count-1] == "\r") {
array_splice($row, count($row) - 1, 1);
}
//CHECK IF HADER COUNT == ROW COUNT
if (count($header) == count($row)) {
array_push($arrrr,array_combine($newhead,$row));
}
}
//CONVERT ARRAY TO JSON
$json = json_encode($arrrr);
//Remove backslasesh from json key and and value to remove \r
$clean = stripslashes($json);
//CONVERT ARRAY TO JSON AGAIN FOR EXPORT
$jsonagain = json_encode($clean);
return $jsonagain;
}

PHP Function that can return value from an array key a dynamic number of levels deep

Using PHP, I would like to write a function that accomplishes what is shown by this pseudo code:
function return_value($input_string='array:subArray:arrayKey')
{
$segments = explode(':',$input_string);
$array_depth = count(segments) - 1;
//Now the bit I'm not sure about
//I need to dynamically generate X number of square brackets to get the value
//So that I'm left with the below:
return $array[$subArray][$arrayKey];
}
Is the above possible? I'd really appreciate some pointer on how to acheive it.
You can use a recursive function (or its iterative equivalent since it's tail recursion):
function return_value($array, $input_string) {
$segments = explode(':',$input_string);
// Can we go next step?
if (!array_key_exists($segments[0], $array)) {
return false; // cannot exist
}
// Yes, do so.
$nextlevel = $array[$segments[0]];
if (!is_array($nextlevel)) {
if (1 == count($segments)) {
// Found!
return $nextlevel;
}
// We can return $nextlevel, which is an array. Or an error.
return false;
}
array_shift($segments);
$nextsegments = implode(':', $segments);
// We can also use tail recursion here, enclosing the whole kit and kaboodle
// into a loop until $segments is empty.
return return_value($nextlevel, $nextsegments);
}
Passing one object
Let's say we want this to be an API and pass only a single string (please remember that HTTP has some method limitation in this, and you may need to POST the string instead of GET).
The string would need to contain both the array data and the "key" location. It's best if we send first the key and then the array:
function decodeJSONblob($input) {
// Step 1: extract the key address. We do this is a dirty way,
// exploiting the fact that a serialized array starts with
// a:<NUMBEROFITEMS>:{ and there will be no "{" in the key address.
$n = strpos($input, ':{');
$items = explode(':', substr($input, 0, $n));
// The last two items of $items will be "a" and "NUMBEROFITEMS"
$ni = array_pop($items);
if ("a" != ($a = array_pop($items))) {
die("Something strange at offset $n, expecting 'a', found {$a}");
}
$array = unserialize("a:{$ni}:".substr($input, $n+1));
while (!empty($items)) {
$key = array_shift($items);
if (!array_key_exists($key, $array)) {
// there is not this item in the array.
}
if (!is_array($array[$key])) {
// Error.
}
$array = $array[$key];
}
return $array;
}
$arr = array(
0 => array(
'hello' => array(
'joe','jack',
array('jill')
)));
print decodeJSONblob("0:hello:1:" . serialize($arr));
print decodeJSONblob("0:hello:2:0" . serialize($arr));
returns
jack
jill
while asking for 0:hello:2: would get you an array { 0: 'jill' }.
you could use recursion and array_key_exists to walk down to the level of said key.
function get_array_element($key, $array)
{
if(stripos(($key,':') !== FALSE) {
$currentKey = substr($key,0,stripos($key,':'));
$remainingKeys = substr($key,stripos($key,':')+1);
if(array_key_exists($currentKey,$array)) {
return ($remainingKeys,$array[$currentKey]);
}
else {
// handle error
return null;
}
}
elseif(array_key_exists($key,$array)) {
return $array[$key];
}
else {
//handle error
return null;
}
}
Use a recursive function like the following or a loop using references to array keys
<?php
function lookup($array,$lookup){
if(!is_array($lookup)){
$lookup=explode(":",$lookup);
}
$key = array_shift($lookup);
if(!isset($array[$key])){
//throw exception if key is not found so false values can also be looked up
throw new Exception("Key does not exist");
}else{
$val = $array[$key];
if(count($lookup)){
return lookup($val,$lookup);
}
return $val;
}
}
$config = array(
'db'=>array(
'host'=>'localhost',
'user'=>'user',
'pass'=>'pass'
),
'data'=>array(
'test1'=>'test1',
'test2'=>array(
'nested'=>'foo'
)
)
);
echo "Host: ".lookup($config,'db:host')."\n";
echo "User: ".lookup($config,'db:user')."\n";
echo "More levels: ".lookup($config,'data:test2:nested')."\n";
Output:
Host: localhost
User: user
More levels: foo

How to use php array+string in html?

I am using PL/pgsql RETURNS TABLE to get the below output using pg_fetch_all in PHP
array(4) {
[0]=> array(1)
{ ["not_actual_values"]=> string(88) "("var1","var2",var3,var4,date1,int,int,int,var5,int,int,int,int)" }
[1]=> array(1)
{ ["not_actual_values"]=> string(89) "("var1","var2",var3,var4,date1,int,int,int,var5,int,int,int,int)" }
[2]=> array(1)
{ ["not_actual_values"]=> string(88) "("var1","var2",var3,var4,date1,int,int,int,var5,int,int,int,int)" }
[3]=> array(1)
{ ["not_actual_values"]=> string(89) "("var1","var2",var3,var4,date1,int,int,int,var5,int,int,int,int)" }
}
I am unable to use the above output in HTML. I tried using php explode but it didnt work I got zero array. Also, What confuses me I am getting quotes in first two variable and not in others.
Update
I used below function but I got zero array
function pgArrayToPhp($text) {
if(is_null($text)) {
return array();
} else if(is_string($text) && $text != '{}') {
$text = substr($text, 1, -1);// Removes starting "{" and ending "}"
if(substr($text, 0, 1) == '"') {
$text = substr($text, 1);
}
if(substr($text, -1, 1) == '"') {
$text = substr($text, 0, -1);
}
// If double quotes are present, we know we're working with a string.
if(strstr($text, '"')) { // Assuming string array.
$values = explode('","', $text);
} else { // Assuming Integer array.
$values = explode(',', $text);
}
$fixed_values = array();
foreach($values as $value) {
$value = str_replace('\\"', '"', $value);
$fixed_values[] = $value;
}
return $fixed_values;
} else {
return array();
}
}
How can i do this ?
Your inner values are arrays, not strings, you need to take that into account:
function pgArraytoPhp($array) {
foreach ($array as $row) { // $row is an inner array here!
actuallyDoParsing($row[0]); // Parse row's first element,
// which will be the string you want.
}
}
Depending on what you need, you'll return the accumulated result of all of those actuallyDoParsing() calls.
This is the answer that I have come up with. Though it is not neat but it seems to be working as expected now
$fetch=pg_fetch_all($query); //fetching data from postgresql
$count=count($fetch);
for ($j=0;$j<$count;$j++) {
$a = $fetch[$j]['not_actual_values'];
$b = array(explode("," , $a));
$count2=count($b[0]);
foreach ($b as $f) { echo '<tr>';
for ($i=0;$i<$count2;$i++){
echo '<td><input type="text" readonly value='.$f[$i].'>';
} } }
But now the problem is raw data contains noise as in "(" so that is spoiling the output.
Thank you all for your efforts.

Parsing a weird malformed ini

I have a really broken/weird INI file that looks like this.
RowID=11668
Name=SCNA DaCe
PPA
Relation=Family
RowID=31999
Name=PCA
RowID=11593
Name=CRMLEVEL
Relation=Family
If possible, end up as
array("11668" => array("name"=> "SCNA DaCe", "relation"=>"Family", "ppa"=>true));
Linebreaks are separated based on RowID instead of a proper [section] and I have no idea how I can read this, any tips on where to start?
There is inconsistent casing, certain things don't have values (like PPA by itself on a line), not all key=vals are defined for each case.
For something like this, an array of objects comes in handy.
http://www.laprbass.com/RAY_temp_dylan.php
<?php // RAY_temp_dylan.php
error_reporting(E_ALL);
echo '<pre>';
$str = <<<END
RowID=11668
Name=SCNA DaCe
PPA
Relation=Family
RowID=31999
Name=PCA
RowID=11593
Name=CRMLEVEL
Relation=Family
END;
// SIMULATE READING WITH file()
$arr = explode(PHP_EOL, $str);
// COLLECT THE NORMALIZED DATA HERE
$out = array();
$obj = new stdClass;
// USE AN ITERATOR ON EACH ROW
foreach ($arr as $row)
{
// SKIP BLANK LINES
$row = trim($row);
if (empty($row)) continue;
// FOR EACH ROWID CREATE A NEW OBJECT
if (FALSE !== strpos($row, 'RowID'))
{
// SAVE THE OLD OBJECT
$out[] = $obj;
$obj = new stdClass;
$obj->RowID = end(explode('=', $row));
}
// FOR REMAINING ELEMENTS THAT ARE KEY-VALUE PAIRS
if (FALSE !== strpos($row, '='))
{
$key = current(explode('=', $row));
$val = end(explode('=', $row));
$obj->$key = $val;
}
// FOR REMAINING ELEMENTS THAT ARE NOT KEY-VALUE PAIRS
else
{
$obj->$row = TRUE;
}
}
// SAVE LAST ELEMENT AT EOF
$out[] = $obj;
// DISCARD THE ZERO "STARTER" ELEMENT
unset($out[0]);
var_dump($out);
You would have to roll your own custom solution to parse this INI file as PHP's built in parse_ini_file is based on PHP's own php.ini format constraints. So it has to be valid PHP.
For your purposes if the requirements are as simple as key/value pairs on each line with the exception of the one-off stranded value as a default boolean true then you could do something like the following.
function my_parse_ini($ini_file_name) {
$ini = file($ini_file_name, FILE_IGNORE_NEW_LINES);
$return = array();
$row = null;
foreach ($ini as $key => $value) {
if ($value == '') {
$row = null;
continue;
}
#list($k, $v) = explode('=',$value);
if ($v === null) {
$v = true;
}
if ($row === null) {
$row = $v;
$return[$row] = array();
continue;
}
$return[$row][$k] = $v;
}
return $return;
}
/* usage */
var_dump(my_parse_ini('test.ini'));
This would output the following for your sample ini file....
array(2) {
[11668]=>
array(4) {
["Name"]=>
string(3) "PCA"
["PPA"]=>
bool(true)
["Relation"]=>
string(6) "Family"
["RowID"]=>
string(5) "31999"
}
[11593]=>
array(2) {
["Name"]=>
string(8) "CRMLEVEL"
["Relation"]=>
string(6) "Family"
}
}

Form a new string with data from an array PHP

I would need to reduce the quantity of these numbers and present them in a more concise way, instead of presenting several lines of numbers with the same "prefix" or "root". For example:
If I have an array like this, with several strings of numbers (obs: only numbers and the array is already sorted):
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
The string: 123456 is the same in all elements of the array, so it would be the root or the prefix of the number. According to the above array I would get a result like this:
//The numbers in brackets represent the sequence of the following numbers,
//instead of showing the rows, I present all the above numbers in just one row:
$stringFormed = "123456[4-5][7-9]";
Another example:
$array2 = array(
"1234",
"1235",
"1236",
"1247",
"2310",
"2311",
);
From the second array, I should get a result like this:
$stringFormed1 = "123[4-7]";
$stringFormed2 = "1247";
$stringFormed3 = "231[0-1]";
Any idea?
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
//find common string positions for all elements
$res = array();
foreach($array as $arr){
for($i=0;$i<strlen($arr);$i++){
$res[$i][$arr[$i]] = $arr[$i];
}
}
//make final string
foreach($res as $pos){
if(count($pos)==1)
$str .= implode('',$pos);
else{
//u may need to sort these values if you want them in order
$end = end($pos);
$first = reset($pos);
$str .="[$first-$end]";
}
}
echo $str; // "123456[4-5][7-9]";
Well, as I understand you want the final string with unique characters. (i'm not sure if you want it ordered)
So, first implode to create the string
$stringFormed = implode("", $array);
Then we get the unique chars :
$stringFormed=implode("",array_unique(str_split($stringFormed)));
OUTPUT: 123456789
That as a solution for first example but i didn't thought there could be several roots.
By the way i'm not sure it's well coded...
<?php
function longest_common_substring($words)
{
$words = array_map('strtolower', array_map('trim', $words));
$sort_by_strlen = create_function('$a, $b', 'if (strlen($a) == strlen($b)) { return strcmp($a, $b); } return (strlen($a) < strlen($b)) ? -1 : 1;');
usort($words, $sort_by_strlen);
// We have to assume that each string has something in common with the first
// string (post sort), we just need to figure out what the longest common
// string is. If any string DOES NOT have something in common with the first
// string, return false.
$longest_common_substring = array();
$shortest_string = str_split(array_shift($words));
while (sizeof($shortest_string)) {
array_unshift($longest_common_substring, '');
foreach ($shortest_string as $ci => $char) {
foreach ($words as $wi => $word) {
if (!strstr($word, $longest_common_substring[0] . $char)) {
// No match
break 2;
} // if
} // foreach
// we found the current char in each word, so add it to the first longest_common_substring element,
// then start checking again using the next char as well
$longest_common_substring[0].= $char;
} // foreach
// We've finished looping through the entire shortest_string.
// Remove the first char and start all over. Do this until there are no more
// chars to search on.
array_shift($shortest_string);
}
// If we made it here then we've run through everything
usort($longest_common_substring, $sort_by_strlen);
return array_pop($longest_common_substring);
}
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
$result= longest_common_substring($array);
for ($i = strlen($result); $i < strlen($array[0]); $i++) {
$min=intval($array[0][$i]);
$max=$min;
foreach ($array as $string) {
$val = intval($string[$i]);
if($val<$min)
$min=$val;
elseif($val>$max)
$max=$val;
}
$result.='['.$min.'-'.$max.']';
}
echo $result;
?>

Categories