PHP for loop stops too early - php

I have a loop which increments the limit of the content which is showing on a website (json content).
The problem is that the loop stops at 50. The links that are generated with the incrementation are working fine when I'm calling them in the browser. The content is shown.
But I store only the content of the first 50 and then it stops.
public static function getAllCustomers() {
$rest = Rest::getInstance();
$spaces = self::getSpaces();
$customers = array();
$path = SpacePath::buildPath();
for ($i = 0;
; $i += Paths::$MAX_CONTENT_LENGTH) {
$temp = $path . '?start=' . $i . '&limit=50';
$content = Helper::toArray($temp);
print_r($temp);
// print_r(empty($content['results']));
if (!empty($content['results'])) {
foreach ($content ['results'] as $space) {
if (!preg_match('|^(.*?)-([0-9]+)|i', $space ['name'], $matches)) {
continue;
}
$customer = (object) array(
'name' => $matches [0],
'ident' => $matches [1],
'id' => $matches [2],
'space_key' => $space ['key'],
'options' => array()
);
$customers [] = $customer;
}
break;
}
}
print_r($customers);
return $customers;
}

Here, let me reformat your code so you can see what relates to what...
public static function getAllCustomers()
{
$rest = Rest::getInstance();
$spaces = self::getSpaces();
$customers = array();
$path = SpacePath::buildPath();
for ($i = 0; ; $i += Paths::$MAX_CONTENT_LENGTH)
{
$temp = $path . '?start=' . $i . '&limit=50';
$content = Helper::toArray($temp);
print_r($temp);
//print_r(empty($content['results']));
if (!empty($content['results']))
{
foreach ($content ['results'] as $space)
{
if (!preg_match('|^(.*?)-([0-9]+)|i', $space ['name'], $matches))
{
continue;
}
$customer = (object) array('name' => $matches [0]
,'ident' => $matches [1]
,'id' => $matches [2]
,'space_key' => $space ['key']
,'options' => array()
);
$customers [] = $customer;
}
break; // oops
}
}
print_r($customers);
return $customers;
}
You'll notice I added a comment to your break statement. ;)

Related

get_query_var mergin two query variable

I registered two query varaible 'star' & 'cord'
And when I visit https://website.com/blog/star-4-5/cord-Corded/
and use $star = explode( '-', get_query_var('star', '') );
$star output is shows as
Array ( [0] => 4 [1] => 5/cord [2] => Corded )
and $cord output is shows as 'Empty'
While $star should show Array ( [0] => 4 [1] => 5 )
and $cord should show 'Corded '
function trimmer_register_query_vars( $vars ) {
$vars[] = 'brand';
$vars[] = 'price';
$vars[] = 'water';
$vars[] = 'star';
$vars[] = 'cord';
return $vars;}add_filter( 'query_vars', 'trimmer_register_query_vars' );
Here's written rule I used for it, it automatically rewrite a combination of all queries.
function generate_rewrite_rules($keys) {
$total_keys = count($keys);
$rules = array();
for ($i = 1; $i <= $total_keys; $i++) {
$combinations = combinations($keys, $i);
foreach ($combinations as $combination) {
$rule = '^trimmer/';
$query = 'index.php?post_type=trimmer&';
$j = 1;
foreach ($combination as $key) {
$rule .= $key . '-(.+?)/'; // Use non-greedy match (`.+?`) instead of greedy match (`.+`)
$query .= $key . '=$matches[' . $j . ']&';
$j++;
}
$rule = rtrim($rule, '/');
$rule .= '/?$';
$query = rtrim($query, '&');
$rules[] = array(
'rule' => $rule,
'query' => $query,
'top' => true
);
}
}
return $rules;
}
function combinations($keys, $length) {
if ($length == 1) {
return array_map(function($val) {
return array($val);
}, $keys);
}
$result = array();
for ($i = 0; $i < count($keys) - $length + 1; $i++) {
$head = $keys[$i];
$combos = combinations(array_slice($keys, $i + 1), $length - 1);
foreach ($combos as $combo) {
array_unshift($combo, $head);
$result[] = $combo;
}
}
return $result;
}
add_action('init', 'register_trimmer_rules');
function register_trimmer_rules() {
$keys = array('brand', 'price', 'cord', 'water', 'star');
$rules = generate_rewrite_rules($keys);
foreach ($rules as $rule) {
add_rewrite_rule($rule['rule'], $rule['query'], $rule['top']);
}
}

How to Fetch Dynamic Multidimensional Array Elements and Display It Like a Path Name?

I have dynamic multidimensional array that contain directory, sub-directory and file names in a project folder, key indicating a sub-directory name and value indicating file names, if a key equal to number indicating only file and then if a key hasn't any value indicating there is no file at all in a directory. The array look like this :
Array
(
[0] => index.php
[src] => Array
(
[src2] => Array
(
[src3] => Array
(
[0] => test_src3.php
)
[0] => Array
(
[0] => test_src2.php
)
)
[0] => test_src.php
)
[src_test] => Array
(
[New Folder] => Array
(
)
[src_test2] => Array
(
[New Folder] => Array
(
)
[src_test3] => Array
(
)
)
)
[1] => test.php
)
The number of dimensions might be change based on sub directories that found in a folder path inputted by user (this program is used by a person in their local).
How could i fetch those array elements so that the result would be like this :
array(
[0] => src/src2/src3/
[1] => src_test/New Folder/
[2] => src_test/src_test2/New Folder/
[3] => src_test/src_test2/src_test3/
)
By the way i have a function to achieve this :
<?php
// Get specific element where the first index is 1 instead of 0
function getAtPos($tmpArray,$pos) {
$keys = array_keys($tmpArray);
return array($keys[$pos-1] => $tmpArray[$keys[$pos-1]]);
}
// Get all Keys that has String type only
function getKeyStr(array $mixed, $numbIdx){
$results = [];
$tmp = array_keys($mixed);
$ii = 0;
for ($i=1; $i <= $numbIdx; $i++) {
$keyArr = getAtPos($tmp, $i);
if (is_string($keyArr[$ii])) {
$results[] = $keyArr[$ii];
}
$ii++;
}
return $results;
}
function getKeyPaths(array $tree, $glue = '/', $return_array = true){
$paths = "";
$result = [];
foreach ($tree as $key => &$mixed) {
if (is_array($mixed) && !is_int($key)) {
$path = $key . $glue;
$retArrFalse = false;
$jlhMixed = count($mixed);
$getKeyStr = getKeyStr($mixed, $jlhMixed);
$jlhKeyStr = count($getKeyStr);
if ($jlhKeyStr < 2) {
$repeat = getKeyPaths($mixed, $glue, $retArrFalse);
$paths .= $path . $repeat;
if ($return_array) {
$paths .= "|";
}
}elseif($jlhKeyStr > 1) {
for ($i=0; $i < $jlhKeyStr; $i++) {
$idxAsso = $getKeyStr[$i];
$jlhKeySub = count($mixed[$idxAsso]);
$path2 = $idxAsso . $glue;
if ($jlhKeySub > 0) {
$paths .= $path . $path2 . getKeyPaths($mixed[$idxAsso], $glue, $retArrFalse);
if ($return_array) {
$paths .= "|";
}
}else{
$paths .= $path . $path2;
if ($return_array) {
$paths .= "|";
}
} // END of if else
} // END of for loop
} // END of elseif
}
} // END of foreach
if ($return_array) {
return explode("|", trim($paths, "|"));
}
return $paths;
}
the above function does not result like what i expected:
Array
(
[0] => src/src2/src3/
[1] => src_test/New Folder/
[2] => src_test/src_test2/New Folder/src_test3/
)
How do i achieve this ?
Any help would be appreciated !
UPDATE
I have modified my function trying to solve this:
<?php
// To get spesific element on dynamic associative array
function getAtPos($tmpArray,$pos) { // $pos is an index order starting with 1 instead of 0
$keys = array_keys($tmpArray);
return array($keys[$pos-1] => $tmpArray[$keys[$pos-1]]);
}
// Get key string type (associative) only in the given array
function getKeyStr(array $mixed, $numbIdx){
$results = [];
$tmp = array_keys($mixed); // change key to element (as array number).
$ii = 0;
for ($i=1; $i <= $numbIdx; $i++) {
$keyArr = getAtPos($tmp, $i);
if (is_string($keyArr[$ii])) {
$results[] = $keyArr[$ii];
}
$ii++;
}
return $results; // Return all second dimension sub-keys of the given array (parent)
}
// EDITED !
function getKeyPaths2(array $tree, $glue = '/', $return_array = true, $goToIfElse = false, $saveSameParent = []){
$paths = "";
$result = [];
$iFor = 0;
foreach ($tree as $key => &$mixed) {
if (is_array($mixed) && !is_int($key)) {
$path = $key . $glue;
$retArrFalse = false;
$jlhMixed = count($mixed);
$getKeyStr = getKeyStr($mixed, $jlhMixed); // Contain sub-keys of the second dimension of the parent
$jlhKeyStr = count($getKeyStr); // Count number of sub-keys of second dimension of parent
if ($goToIfElse !== false) {
$jlhKeyStr = $goToIfElse;
$iFor++;
unset($mixed);
$mixed = $tree;
$jlhMixed = count($mixed);
$getKeyStr = getKeyStr($mixed, $jlhMixed); // Contain sub-keys of the second dimension of the
$jlhKeyStr = count($getKeyStr); // Count number of sub-keys of second dimension of parent
}
if ($jlhKeyStr < 2) {
$repeat = getKeyPaths2($mixed, $glue, $retArrFalse);
$paths .= $path . $repeat;
if (!$return_array && $jlhKeyStr < 1) {
$paths .= "|";
}
}elseif($jlhKeyStr > 1) {
for ($i=$iFor; $i < $jlhKeyStr; $i++) {
$idxAsso = $getKeyStr[$i];
$jlhKeySub = count($mixed[$idxAsso]);
$path2 = $idxAsso . $glue;
if ($jlhKeySub > 0) {
$paths .= $path . $path2;
// TEST
$pecah = explode("|", $paths);
$saveSameParent[0] = end($pecah);
if ($return_array) {
$paths .= "|";
}
$paths .= $path . $path2 . getKeyPaths2($mixed[$idxAsso], $glue, $retArrFalse, $jlhKeyStr, $saveSameParent);
if ($return_array) {
$paths .= "|";
}
}else{
if ($goToIfElse !== false) {
$paths .= $path;
$paths .= "|";
$paths .= $saveSameParent[0] . $path2;
$paths .= "|";
}else{
$paths .= $path . $path2;
}
if ($return_array || $goToIfElse !== false) {
$paths .= "|";
}
} // END of if else
} // END of for loop
} // END of elseif
}
} // END of foreach
if ($return_array) {
return explode("|", trim($paths, "|"));
}
return $paths;
}
But this only works with my example array that i showed above.
If the given array like this, this would not work:
<?php
$tree = [];
$tree[0] = "index.php";
$tree["src"]["src2"]["src3"][0] = "test_src3.php";
$tree["src"]["src2"][0][0] = "test_src2.php";
$tree["src"][0] = "test_src.php";
$tree["src_test"]["New Folder"] = array();
$tree["src_test"]["src_test2"]["New Folder"] = array();
$tree["src_test"]["src_test2"]["src_test3.1"] = array();
$tree["src_test"]["src_test2"]["src_test3.2"] = array();
$tree["src_test"]["src_test2"]["src_test3.1"]["src_test3.1.1"] = array();
$tree["src_test"]["src_test2"]["src_test3.2"]["src_test3.2.1"]["src_test3.2.2"]["src_test3.2.3"] = array("test_src4.php", "test_src5.php");
The result would be :
Array
(
[0] => src/src2/src3/
[1] => src_test/New Folder/
[2] => src_test/src_test2/
[3] => src_test/src_test2/New Folder/src_test3.1/New Folder/src_test3.1/src_test3.1.1/src_test3.1.1/
[4] => New Folder/src_test3.2/New Folder/src_test3.2/src_test3.2.1/src_test3.2.1/src_test3.2.2/src_test3.2.3/
[5] => src_test3.1/src_test3.2/src_test3.1/src_test3.2/src_test3.2.1/src_test3.2.1/src_test3.2.2/src_test3.2.3/
)

PHP Should I Use Filesystem DB to store JSON Files

My question is regarding the use of the file system as a database to simply hold JSON files.
I have came up with this following code, not perfect at all. which I found very easy to store and extract data, using JSON files.
My question is, will this DB be good for any large projects? will it work fast? or is the limitation to use this kind of approach is simply security related?
Is there some kind of built-in solution by PHP for this kind of things?
Any input on this matter from people who know will be appreciated...
class JDB{
public $path;
function JDB( $path = __DIR__.'/jdb/' ){
$this->path = $path;
if( !file_exists($this->path) ) mkdir($this->path);
}
function p($t){
return $this->path.$t.'.json';
}
function get($t){
return json_decode(file_get_contents( $this->p($t) ));
}
function set($t,$c){
return file_put_contents( $this->p($t), json_encode($c,JSON_PRETTY_PRINT) );
}
function create( $t, $d = [] ){
$s = file_put_contents( $this->p($t), json_encode($d) );
return $s;
}
function destroy(){
$files = glob($this->path.'*'); // get all file names present in folder
foreach($files as $file){ // iterate files
if(is_file($file))
unlink($file); // delete the file
}
}
function delete( $t ){
$s = unlink( $this->p($t) );
return $s;
}
function insert( $t, $d = null ){
if($d) $d['__uid'] = $t.'_'.$this->uid();
$c = $this->get($t);
array_push($c,$d);
$s = $this->set($t,$c);
if($s) return $d['__uid'];
}
function update($t,$conditions,$u){
$c = $this->get($t);
$this->search($c,$conditions,function($object) use (&$c,$u){
foreach ($u as $key => $value) {
$object->$key = $value;
}
});
$this->set($t,$c);
}
function remove($t,$conditions){
$c = $this->get($t);
$this->search($c,$conditions,function($object,$key) use (&$c){
unset($c[$key]);
});
$this->set($t,$c);
}
function search( $c, $conditions = [], $fn ){
$l = count($conditions);
foreach ($c as $key => $object) {
$f = 0;
foreach ($conditions as $k => $v) {
if( property_exists($object,$k) && ($object->$k == $v) ){
$f++;
if( $f==$l ) $fn($object,$key);
}else break;
}
}
}
function select( $t, $conditions = [] ){
$c = $this->get($t);
$r = [];
$this->search($c,$conditions,function($object) use (&$r){
array_push($r,$object);
});
if (count($r) == 0) return false;
if (count($r) == 1) return $r[0];
return $r;
}
function count($t){
$c = $this->get($t);
return count($c);
}
function uid($length = 20) {
$c = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$cl = strlen($c);
$uid = '';
for ($i = 0; $i < $length; $i++) {
$uid .= $c[rand(0, $cl - 1)];
}
return $uid;
}
}
very simple, the question if this is even possible...
How To Use
$db = new JDB();
$db->create('users');
$db->create('pages');
$user_uid = $db->insert('users',[
'name' => 'a',
'password' => 'hello world',
'pages' => []
]);
$user_uid = $db->insert('users',[
'name' => 'b',
'password' => 'hello world',
'pages' => []
]);
$page_uid = $db->insert('pages',[
'name' => 'page 1',
'content' => 'hello world',
'users' => [$user_uid]
]);
$user = $db->select('users',['name' => 'a']);
$page = $db->select('pages',['users' => [$user_uid]]);
$db->update('users',['name' => 'b'],['pages' => [$page->__uid]]);
$db->remove('users',['name' => 'a']);

How to append a file with for loop based data in php

I want to append a txt file with for loop data using php. Here is my code
$post_array = array('hdnItemTypeID', 'hdnItemType', 'hdnItemCode', 'hdnCost', 'txtDescription');
foreach ($post_array as $pos) {
foreach ($_POST[$pos] as $id => $row) {
$_POST[$pos][$id] = $row;
}
}
$ids = $_POST['hdnItemTypeID'];
$ItemTypeID = $_POST['hdnItemTypeID'];
$ItemType = $_POST['hdnItemType'];
$ItemCode = $_POST['hdnItemCode'];
//$Discount = $_POST['txtDiscount'];
$Discount = '0';
$UnitCost = $_POST['hdnCost'];
//$Amount = $UnitPrice + $Discount;
$Description = $_POST['txtDescription'];
$size = count($ids);
for ($i = 0; $i < $size; $i++) {
// Check for part id
if (empty($ids[$i])) {
continue;
}
$items = array(
':ItemTypeID' => $ItemTypeID[$i],
':ItemType' => $ItemType[$i],
':ItemCode' => $ItemCode[$i],
':Description' => $Description[$i],
':UnitCost' => $UnitCost[$i],
':Amount' => $UnitCost[$i] +$Discount,
':Discount' => $Discount
);
file_put_contents('Check.txt', print_r($items,true));
}
But only single array is getting is getting in the file. How to get althe array values in it?
file_put_contents by default overwrites everything. Use:
file_put_contents('Check.txt', $items, FILE_APPEND);
REFERENCE
I think you cant use
file_put_contents('Check.txt', print_r($items,true), FILE_APPEND);
See http://php.net/manual/fr/function.file-put-contents.php

PHP - Array to CSV by Column

issue: I have an associative array, where all the keys represent the csv headers and the values in each $key => array.. represent the items in that column.
Research: To my knowledge, fputcsv likes to go in row by row, but this column-based array is making that complicated. I have not found any function out there that accomplishes this.
Example:
Array(
['fruits'] => Array(
[0] => 'apples',
[1] => 'oranges',
[2] => 'bananas'
),
['meats'] => Array(
[0] => 'porkchop',
[1] => 'chicken',
[2] => 'salami',
[3] => 'rabbit'
),
)
Needs to become:
fruits,meats
apples,porkchop
oranges,chicken
bananas,salami
,rabbit
Why it's hard:
You need to know the max number of rows to make blank spots.
I had to write my own function. Thought maybe it might help someone else!
/*
* The array is associative, where the keys are headers
* and the values are the items in that column.
*
* Because the array is by column, this function is probably costly.
* Consider a different layout for your array and use a better function.
*
* #param $array array The array to convert to csv.
* #param $file string of the path to write the file.
* #param $delimeter string a character to act as glue.
* #param $enclosure string a character to wrap around text that contains the delimeter
* #param $escape string a character to escape the enclosure character.
* #return mixed int|boolean result of file_put_contents.
*/
function array_to_csv($array, $file, $delimeter = ',', $enclosure = '"', $escape = '\\'){
$max_rows = get_max_array_values($array);
$row_array = array();
$content = '';
foreach ($array as $header => $values) {
$row_array[0][] = $header;
$count = count($values);
for ($c = 1; $c <= $count; $c++){
$value = $values[$c - 1];
$value = preg_replace('#"#', $escape.'"', $value);
$put_value = (preg_match("#$delimeter#", $value)) ? $enclosure.$value.$enclosure : $value;
$row_array[$c][] = $put_value;
}
// catch extra rows that need to be blank
for (; $c <= $max_rows; $c++) {
$row_array[$c][] = '';
}
}
foreach ($row_array as $cur_row) {
$content .= implode($delimeter,$cur_row)."\n";
}
return file_put_contents($file, $content);
}
And this:
/*
* Get maximum number of values in the entire array.
*/
function get_max_array_values($array){
$max_rows = 0;
foreach ($array as $cur_array) {
$cur_count = count($cur_array);
$max_rows = ($max_rows < $cur_count) ? $cur_count : $max_rows;
}
return $max_rows;
}
New Way (using a class)
I wrote a class for this a while later, which I'll provide for anyone looking for one now:
class CSVService {
protected $csvSyntax;
public function __construct()
{
return $this;
}
public function renderCSV($contents, $filename = 'data.csv')
{
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename="' . $filename . '"');
echo $contents;
}
public function CSVtoArray($filename = '', $delimiter = ',') {
if (!file_exists($filename) || !is_readable($filename)) {
return false;
}
$headers = null;
$data = array();
if (($handle = fopen($filename, 'r')) !== false) {
while (($row = fgetcsv($handle, 0, $delimiter, '"')) !== false) {
if (!$headers) {
$headers = $row;
array_walk($headers, 'trim');
$headers = array_unique($headers);
} else {
for ($i = 0, $j = count($headers); $i < $j; ++$i) {
$row[$i] = trim($row[$i]);
if (empty($row[$i]) && !isset($data[trim($headers[$i])])) {
$data[trim($headers[$i])] = array();
} else if (empty($row[$i])) {
continue;
} else {
$data[trim($headers[$i])][] = stripcslashes($row[$i]);
}
}
}
}
fclose($handle);
}
return $data;
}
protected function getMaxArrayValues($array)
{
return array_reduce($array, function($carry, $item){
return ($carry > $c = count($item)) ? $carry : $c;
}, 0);
}
private function getCSVHeaders($array)
{
return array_reduce(
array_keys($array),
function($carry, $item) {
return $carry . $this->prepareCSVValue($item) . $this->csvSyntax->delimiter;
}, '') . "\n";
}
private function prepareCSVValue($value, $delimiter = ',', $enclosure = '"', $escape = '\\')
{
$valueEscaped = preg_replace('#"#', $escape . '"', $value);
return (preg_match("#$delimiter#", $valueEscaped)) ?
$enclosure . $valueEscaped . $enclosure : $valueEscaped;
}
private function setUpCSVSyntax($delimiter, $enclosure, $escape)
{
$this->csvSyntax = (object) [
'delimiter' => $delimiter,
'enclosure' => $enclosure,
'escape' => $escape,
];
}
private function getCSVRows($array)
{
$n = $this->getMaxArrayValues($array);
$even = array_values(
array_map(function($columnArray) use ($n) {
for ($i = count($columnArray); $i <= $n; $i++) {
$columnArray[] = '';
}
return $columnArray;
}, $array)
);
$rowString = '';
for ($row = 0; $row < $n; $row++) {
for ($col = 0; $col < count($even); $col++) {
$value = $even[$col][$row];
$rowString .=
$this->prepareCSVValue($value) .
$this->csvSyntax->delimiter;
}
$rowString .= "\n";
}
return $rowString;
}
public function arrayToCSV($array, $delimiter = ',', $enclosure = '"', $escape = '\\', $headers = true) {
$this->setUpCSVSyntax($delimiter, $enclosure, $escape);
$headersString = ($headers) ? $this->getCSVHeaders($array) : '';
$rowsString = $this->getCSVRows($array);
return $headersString . $rowsString;
}
}
$data = array(
'fruits' => array(
'apples',
'oranges',
'bananas'
),
'meats' => array(
'porkchop',
'chicken',
'salami',
'rabbit'
),
);
$combined = array(array('fruits', 'meats'));
for($i = 0; $i < max(count($data['fruits']), count($data['meats'])); $i++)
{
$row = array();
$row[] = isset($data['fruits'][$i]) ? $data['fruits'][$i] : '';
$row[] = isset($data['meats'][$i]) ? $data['meats'][$i] : '';
$combined[] = $row;
}
ob_start();
$fp = fopen('php://output', 'w');
foreach($combined as $row)
fputcsv($fp, $row);
fclose($fp);
$data = ob_get_clean();
var_dump($data);
Conversion to csv and parsing of the array can be done in the same loop. Or did you mean that there might be more columns? This code can be easily modified for the general type of the array. Like this, for any number of the columns
$data = array(
'fruits' => array(
'apples',
'oranges',
'bananas'
),
'meats' => array(
'porkchop',
'chicken',
'salami',
'rabbit'
),
);
$heads = array_keys($data);
$maxs = array();
foreach($heads as $head)
$maxs[] = count($data[$head]);
ob_start();
$fp = fopen('php://output', 'w');
fputcsv($fp, $heads);
for($i = 0; $i < max($maxs); $i++)
{
$row = array();
foreach($heads as $head)
$row[] = isset($data[$head][$i]) ? $data[$head][$i] : '';
fputcsv($fp, $row);
}
fclose($fp);
$data = ob_get_clean();
var_dump($data);

Categories