Related
I have to change filenames to images/filename and files/filename in Wordpress and I ended up using WP-CLI's search-replace function.
Here is the shell command I execute:
wp search-replace '(")(5\.jpg)' 'images/${2}' wp_postmeta --regex --regex-delimiter='/' --dry-run --skip-columns=meta_key --debug=true
This gives me back message: 0 replacements to be made.
Here is one entry from the database:
a:5:{s:5:"width";i:2048;s:6:"height";i:1536;s:4:"file";s:5:"5.jpg";s:5:"sizes";a:4:{s:9:"thumbnail";a:4:{s:4:"file";s:13:"5-150x150.jpg";s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}s:6:"medium";a:4:{s:4:"file";s:13:"5-300x225.jpg";s:5:"width";i:300;s:6:"height";i:225;s:9:"mime-type";s:10:"image/jpeg";}s:12:"medium_large";a:4:{s:4:"file";s:13:"5-768x576.jpg";s:5:"width";i:768;s:6:"height";i:576;s:9:"mime-type";s:10:"image/jpeg";}s:5:"large";a:4:{s:4:"file";s:14:"5-1024x768.jpg";s:5:"width";i:1024;s:6:"height";i:768;s:9:"mime-type";s:10:"image/jpeg";}}s:10:"image_meta";a:12:{s:8:"aperture";s:1:"0";s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption";s:0:"";s:17:"created_timestamp";s:1:"0";s:9:"copyright";s:0:"";s:12:"focal_length";s:1:"0";s:3:"iso";s:1:"0";s:13:"shutter_speed";s:1:"0";s:5:"title";s:0:"";s:11:"orientation";s:1:"0";s:8:"keywords";a:0:{}}}
I created a custom PHP script as the following:
$data = 'a:5:{s:5:"width";i:2048;s:6:"height";i:1536;s:4:"file";s:5:"5.jpg";s:5:"sizes";a:4:{s:9:"thumbnail";a:4:{s:4:"file";s:13:"5-150x150.jpg";s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}s:6:"medium";a:4:{s:4:"file";s:13:"5-300x225.jpg";s:5:"width";i:300;s:6:"height";i:225;s:9:"mime-type";s:10:"image/jpeg";}s:12:"medium_large";a:4:{s:4:"file";s:13:"5-768x576.jpg";s:5:"width";i:768;s:6:"height";i:576;s:9:"mime-type";s:10:"image/jpeg";}s:5:"large";a:4:{s:4:"file";s:14:"5-1024x768.jpg";s:5:"width";i:1024;s:6:"height";i:768;s:9:"mime-type";s:10:"image/jpeg";}}s:10:"image_meta";a:12:{s:8:"aperture";s:1:"0";s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption";s:0:"";s:17:"created_timestamp";s:1:"0";s:9:"copyright";s:0:"";s:12:"focal_length";s:1:"0";s:3:"iso";s:1:"0";s:13:"shutter_speed";s:1:"0";s:5:"title";s:0:"";s:11:"orientation";s:1:"0";s:8:"keywords";a:0:{}}}';
if (preg_match('/(")(5\.jpg)/', $data)) {
echo "A match was found.";
} else {
echo "A match was not found.";
}
echo '<br>';
$data = preg_replace( '/(")(5\.jpg)/', 'images/${2}', $data );
var_dump($data);
This replaces the data fine, I get result as
a:5:{s:5:"width";i:2048;s:6:"height";i:1536;s:4:"file";s:5:"images/5.jpg" ...
This is the source code of WP-CLI search-replace:
<?php
namespace WP_CLI;
class SearchReplacer {
private $from, $to;
private $recurse_objects;
private $regex;
private $regex_flags;
private $regex_delimiter;
private $logging;
private $log_data;
private $max_recursion;
/**
* #param string $from String we're looking to replace.
* #param string $to What we want it to be replaced with.
* #param bool $recurse_objects Should objects be recursively replaced?
* #param bool $regex Whether `$from` is a regular expression.
* #param string $regex_flags Flags for regular expression.
* #param string $regex_delimiter Delimiter for regular expression.
* #param bool $logging Whether logging.
*/
function __construct( $from, $to, $recurse_objects = false, $regex = false, $regex_flags = '', $regex_delimiter = '/', $logging = false ) {
$this->from = $from;
$this->to = $to;
$this->recurse_objects = $recurse_objects;
$this->regex = $regex;
$this->regex_flags = $regex_flags;
$this->regex_delimiter = $regex_delimiter;
$this->logging = $logging;
$this->clear_log_data();
// Get the XDebug nesting level. Will be zero (no limit) if no value is set
$this->max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) );
}
/**
* Take a serialised array and unserialise it replacing elements as needed and
* unserialising any subordinate arrays and performing the replace on those too.
* Ignores any serialized objects unless $recurse_objects is set to true.
*
* #param array|string $data The data to operate on.
* #param bool $serialised Does the value of $data need to be unserialized?
*
* #return array The original array with all elements replaced as needed.
*/
function run( $data, $serialised = false ) {
return $this->_run( $data, $serialised );
}
/**
* #param int $recursion_level Current recursion depth within the original data.
* #param array $visited_data Data that has been seen in previous recursion iterations.
*/
private function _run( $data, $serialised, $recursion_level = 0, $visited_data = array() ) {
// some unseriliased data cannot be re-serialised eg. SimpleXMLElements
try {
if ( $this->recurse_objects ) {
// If we've reached the maximum recursion level, short circuit
if ( $this->max_recursion != 0 && $recursion_level >= $this->max_recursion ) {
return $data;
}
if ( is_array( $data ) || is_object( $data ) ) {
// If we've seen this exact object or array before, short circuit
if ( in_array( $data, $visited_data, true ) ) {
return $data; // Avoid infinite loops when there's a cycle
}
// Add this data to the list of
$visited_data[] = $data;
}
}
if ( is_string( $data ) && ( $unserialized = #unserialize( $data ) ) !== false ) {
$data = $this->_run( $unserialized, true, $recursion_level + 1 );
}
elseif ( is_array( $data ) ) {
$keys = array_keys( $data );
foreach ( $keys as $key ) {
$data[ $key ]= $this->_run( $data[$key], false, $recursion_level + 1, $visited_data );
}
}
elseif ( $this->recurse_objects && is_object( $data ) ) {
foreach ( $data as $key => $value ) {
$data->$key = $this->_run( $value, false, $recursion_level + 1, $visited_data );
}
}
else if ( is_string( $data ) ) {
if ( $this->logging ) {
$old_data = $data;
}
if ( $this->regex ) {
$search_regex = $this->regex_delimiter;
$search_regex .= $this->from;
$search_regex .= $this->regex_delimiter;
$search_regex .= $this->regex_flags;
$data = preg_replace( $search_regex, $this->to, $data );
} else {
$data = str_replace( $this->from, $this->to, $data );
}
if ( $this->logging && $old_data !== $data ) {
$this->log_data[] = $old_data;
}
}
if ( $serialised )
return serialize( $data );
} catch( Exception $error ) {
}
return $data;
}
/**
* Gets existing data saved for this run when logging.
* #return array Array of data strings, prior to replacements.
*/
public function get_log_data() {
return $this->log_data;
}
/**
* Clears data stored for logging.
*/
public function clear_log_data() {
$this->log_data = array();
}
}
I use the exact same preg_replace as used here,
$data = preg_replace( $search_regex, $this->to, $data );
Why this is not working in WP-CLI?
I have index ponter, for example 5-1-key2-3.
And my array has its address:
array(
'5'=>array(
'1'=>array(
'key2'=>array(
'3'=>'here it is - 5-1-key2-3 key address'
)
)
)
)
which equals to
$arr[5][1][key2][3]='here it is - 5-1-key2-3 key address';
I know I can build the recursive function to access this value.
But I'm curious is it possible to achieve this without recursion and building user's functions and/or loops.
Probably it can be done with variable variables feature in php.
You can use this code
$keys = explode('-', '5-1-key2-3');
// start from the root of the array and progress through the elements
$temp = $arr;
foreach ($keys as $key_value)
{
$temp = $temp[$key_value];
}
// this will give you $arr["5"]["1"]["key2"]["3"] element value
echo $temp;
modifications after I got better understanding of the question I think you can do it with eval:
<?php
function getArrValuesFromString($string, $arr) {
$stringArr = '$arr[\'' . str_replace('-', "']['", $string) . '\']';
eval("\$t = " . $stringArr . ";");
return $t;
}
$arr[5][1]['key2'][3] = '1here it is - 5-1-key2-3 key address';
$string = '5-1-key2-3';
echo getArrValuesFromString($string, $arr); //1here it is - 5-1-key2-3 key address
EDIT :
Here is a way I deprecate so much, because of security, but if you are sure of what you are doing :
$key = 'a-b-c-d';
$array = <<your array>>;
$keys = explode('-', $key);
// we can surely do something better like checking for each one if its a string or int then adding or not the `'`
$final_key = "['".implode("']['", $keys)."']";
$result = eval("return \$array{$final_key};");
There is a class I wrote inspired from something I read on the web don't really remember where but anyway, this can helps you :
/**
* Class MultidimensionalHelper
*
* Some help about multidimensional arrays
* like dynamic array_key_exists, set, and get functions
*
* #package Core\Utils\Arrays
*/
class MultidimensionalHelper
{
protected $keySeparator = '.';
/**
* #return string
*/
public function keySeparator()
{
return $this->keySeparator;
}
/**
* #param string $keySeparator
*/
public function setKeySeparator($keySeparator)
{
$this->keySeparator = $keySeparator;
}
/**
* Multidimensional array dynamic array_key_exists
*
* #param $key String Needle
* #param $array Array Haystack
* #return bool True if found, false either
*/
public function exists($key, $array)
{
$keys = explode($this->keySeparator(), $key);
$tmp = $array;
foreach($keys as $k)
{
if(!array_key_exists($k, $tmp))
{
return false;
}
$tmp = $tmp[$k];
}
return true;
}
/**
* Multidimensional array dynamic getter
*
*
* #param $key String Needle
* #param $array Array Haystack
* #return mixed Null if key not exists or the content of the key
*/
public function get($key, $array)
{
$keys = explode($this->keySeparator(), $key);
$lkey = array_pop($keys);
$tmp = $array;
foreach($keys as $k)
{
if(!isset($tmp[$k]))
{
return null;
}
$tmp = $tmp[$k];
}
return $tmp[$lkey];
}
/**
* Multidimensional array dynamic setter
*
* #param String $key
* #param Mixed $value
* #param Array $array Array to modify
* #param Bool $return
* #return Array If $return is set to TRUE (bool), this function
* returns the modified array instead of directly modifying it.
*/
public function set($key, $value, &$array)
{
$keys = explode($this->keySeparator(), $key);
$lkey = array_pop($keys);
$tmp = &$array;
foreach($keys as $k)
{
if(!isset($tmp[$k]) || !is_array($tmp[$k]))
{
$tmp[$k] = array();
}
$tmp = &$tmp[$k];
}
$tmp[$lkey] = $value;
unset($tmp);
}
}
Then use :
$MDH = new MultidimensionalHelper();
$MDH->setKeySeparator('-');
$arr = [
'a' => [
'b' => [
'c' => 'good value',
],
'c' => 'wrong value',
],
'b' => [
'c' => 'wrong value',
]
];
$key = 'a-b-c';
$val = $MDH->get($key, $arr);
var_dump($val);
Here is the content of the get function if you don't find it in Class code :
public function get($key, $array)
{
$keys = explode($this->keySeparator(), $key);
$lkey = array_pop($keys);
$tmp = $array;
foreach($keys as $k)
{
if(!isset($tmp[$k]))
{
return null;
}
$tmp = $tmp[$k];
}
return $tmp[$lkey];
}
For example, I have this kind of code:
<?php
/**
* Order
*
* The WooCommerce order class handles order data.
*
* #class WC_Order
* #version 1.6.4
* #package WooCommerce/Classes
* #category Class
* #author WooThemes
*/
class WC_Order {
/** #public int Order (post) ID */
public $id;
/** #public string Order status. */
public $status;
/** #public string Order date (placed). */
public $order_date;
/** #public string Order date (paid). */
public $modified_date;
/** #public string Note added by the customer. */
public $customer_note;
/** #public array Order (post) meta/custom fields. */
public $order_custom_fields;
global $wpdb, $woocommerce;
if ( empty( $type ) )
$type = array( 'line_item' );
if ( ! is_array( $type ) )
$type = array( $type );
$items = $this->get_items( $type );
$count = 0;
foreach ( $items as $item ) {
if ( ! empty( $item['qty'] ) )
$count += $item['qty'];
else
$count ++;
}
return apply_filters( 'woocommerce_get_item_count', $count, $type, $this );
}
/**
* Return an array of fees within this order.
*
* #access public
* #return array
*/
public function get_fees() {
return $this->get_items( 'fee' );
}
/**
* Return an array of taxes within this order.
*
* #access public
* #return void
*/
public function get_taxes() {
return $this->get_items( 'tax' );
}
/**
* Get taxes, merged by code, formatted ready for output.
*
* #access public
* #return void
*/
public function get_tax_totals() {
$taxes = $this->get_items( 'tax' );
$tax_totals = array();
foreach ( $taxes as $key => $tax ) {
$code = $tax[ 'name' ];
if ( ! isset( $tax_totals[ $code ] ) ) {
$tax_totals[ $code ] = new stdClass();
$tax_totals[ $code ]->amount = 0;
}
$tax_totals[ $code ]->is_compound = $tax[ 'compound' ];
$tax_totals[ $code ]->label = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ];
$tax_totals[ $code ]->amount += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ];
$tax_totals[ $code ]->formatted_amount = woocommerce_price( $tax_totals[ $code ]->amount );
}
return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this );
}
/**
* has_meta function for order items.
*
* #access public
* #return array of meta data
*/
public function has_meta( $order_item_id ) {
global $wpdb;
return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, order_item_id
FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d
ORDER BY meta_key,meta_id", absint( $order_item_id ) ), ARRAY_A );
}
/**
* Get order item meta.
*
* #access public
* #param mixed $item_id
* #param string $key (default: '')
* #param bool $single (default: false)
* #return void
*/
public function get_item_meta( $order_item_id, $key = '', $single = false ) {
return get_metadata( 'order_item', $order_item_id, $key, $single );
}
I want to match all Wordpress hooks: "do_action" and "apply_filters" with three options:
apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this ), file, line number
An example of what i'm trying to do can be seen here:
http://etivite.com/api-hooks/buddypress/trigger/apply_filters/bp_get_total_mention_count_for_user/
http://adambrown.info/p/wp_hooks/hook/activated_plugin?version=3.6&file=wp-admin/includes/plugin.php
I did try to pull something out but with no success:
<?php
$path = $_SERVER['DOCUMENT_ROOT'] . '/wp-content/plugins/iphorm-form-builder';
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) {
if (substr($filename, -3) == 'php') {
$file = file($filename);
if ($file !== false) {
$matches1 = preg_grep( '/do_action\((.+)\);/', $file);
$matches2 = preg_grep( '/apply_filters\((.+)\);/', $file );
$arr = array_filter(array_merge($matches1, $matches2));
$out = '';
echo "found in $filename:";
echo "<pre>";
foreach ($arr as $key => $value) {
$out .= $file[$key-2];
$out .= $file[$key-1];
$out .= $file[$key];
$out .= $file[$key+1];
$out .= $file[$key+2];
}
echo htmlentities($out);
echo "</pre>";
} else {
echo "failed reading to array";
}
}
}
This can be done very simply by taking advantage of built-in shell commands.
<?php
$path = $_SERVER['DOCUMENT_ROOT'] . '/wp-content/plugins/iphorm-form-builder';
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) {
if (substr($filename, -3) == 'php') {
$context = shell_exec('grep -H -n -C4 do_action ' . escapeshellarg($filename));
if (!empty($context)) {
echo "found in $filename:";
echo "<pre>";
echo htmlentities($context);
echo "</pre>";
} else {
echo "failed reading to array";
}
}
}
Relevant documentation:
php shell_exec
Execute command via shell and return the complete output as a string
php escapeshellarg
Escape a string to be used as a shell argument
bash grep
Grep searches the named input FILEs (or standard input if no files are
named, or the file name - is given) for lines containing a match to the
given PATTERN. By default, grep prints the matching lines.
-C NUM, --context=NUM
Print NUM lines of output context. Places a line containing --
between contiguous groups of matches.
-H, --with-filename
Print the filename for each match.
-n, --line-number
Prefix each line of output with the line number within its input
file.
Edit
Depending on how many directories and files you have in your project, it may not be performant. You're basically creating a new process in a new shell for each file. That's not great. If you'd rather get a big dump of data and parse it out later, do this instead:
<?php
$path = $_SERVER['DOCUMENT_ROOT'] . '/wp-content/plugins/iphorm-form-builder';
$grep = shell_exec('grep --include=*.php -RHn -C4 do_action ' . escapeshellarg($path));
$matches = explode("\n--\n", $grep);
if (empty($matches)) {
echo "failed reading to array";
}
else {
foreach ($matches as $match) {
echo "<pre>";
echo htmlentities($match);
echo "</pre>";
}
}
You don't need to loop through file data line by line. Just read the data in a variable and apply regex:
$data = file_get_contents( $filename );
if (preg_match_all(
'~((?:[^\n]*\n){0,4}) *do_action\s*\(\s*([^)]+)\s*\)\s*;[^\n]*\n((?:[^\n]*\n){0,4})~',
$data, $arr)) {
// match found, now dump the results
// $arr[1] will print 4 lines before the match
// $arr[2] will print function arguments for do_action
// $arr[3] will print 4 lines after the match
print_r($arr);
}
This can not be done by regular expressions alone given the limitations of PHP's regular expression engine. Specifically, and it came as a surprise to me, you can not have variable length look behinds.
The reason you need look behinds is if you had the occurrence of do_action or apply_filters on consecutive lines, then the first match will prevent the second match if you had no look aheads, and even if you use look aheads, there is no way to get the previous two rows of the second match without the look behinds. Not to mention I don't even know if you can even include the contents of a look around assertion in the result.
This solution creates a regular expression to find the lines in which the function occurs, and then uses two more regexes to find the lines before and after. I took care to watch out for the start and end of file when designing the regexes.
$offset = 0;
while (preg_match('/^.*?(?:apply_filters|do_action)\s*\(.+?\)\s*;.*(?:\n\r|\n|\r|$)/m', $file, $match, PREG_OFFSET_CAPTURE, $offset))
{
$index = $match[0][1];
$offset = $index + strlen($match[0][0]);
$hasBefore = preg_match('/(?:.*(?:\n\r|\n|\r).*$)|[^\n\r].*$/',
substr($file, 0, $index), $beforeMatch);
$hasAfter = preg_match('/^(?:.*(?:\n\r|\n|\r|$)){0,2}/',
substr($file, $offset), $afterMatch);
if ($hasBefore) print_r($beforeMatch);
print_r($match[0][0]);
if ($hasAfter) print_r($afterMatch);
}
phpFiddle
This only displays two lines before and two lines after. You can use repetition if you want more, but it appears to me from the attempted solution that this was what the o.p. really wanted.
I'm building a platform. Somewhere in my code, there's an array that looks like this (PHP):
$entries = array('p01','p02','g01','g02','a001','a002')
I need to write a script that filters the array based on the first letter. For example, asking for those with the starting letter "p" would give me
$filtered_entries = array('p01','p02');
Similarly, if I asked for those with starting letter "g" or "a" it would give me those as well. Any idea how to accomplish this?
There is an array_filter() function in PHP which you can use to accomplish this:
$filtered = array_filter($array, create_function('$a', 'return $a[0] == "' . $letter . '";'));
I'll leave it to you to generalize the function to handle all the letters.
See: http://www.php.net/manual/en/function.array-filter.php
class FirstCharFilter {
public $char = 'p';
function filter(array $array){
return array_filter($array,array($this,'checkFirstChar'));
}
public function checkFirstChar($a){
return $a[0] == $this->char;
}
}
$filter = new FirstCharFilter();
$filter->char = 'p';
var_dump($filter->filter($array));
$filter->char = 'g';
var_dump($filter->filter($array));
Or if you only need to loop, extend FilterIterator:
class FirstCharIterator extends FilterIterator {
public $char = '';
function accept(){
$string = $this->current();
return is_string($string) && $string[0] == $this->char;
}
}
$iter = new FirstCharIterator(new ArrayIterator($array));
$iter->char = 'p';
foreach($iter as $item) echo $item."\n";
$entries = array('p01','p02','g01','g02','a001','a002');
print_r(
preg_grep('~^p~', $entries) // or preg_grep("~^$letter~",.....
);
http://php.net/manual/en/function.preg-grep.php
function filter_array($array, $letter){
$filtered_array=array();
foreach($array as $key=>$val){
if($val[0]==$letter){
$filtered_array[]=$val;
}
}
return $filtered_array;
}
use it like this to get all p's
$entries = array('p01','p02','g01','g02','a001','a002')
$filtered=filter_array($entries, 'p');
$entries = array('p01','p02','g01','g02','a001','a002');
$filterVar = null;
function filterFunction($v) {
global $filterVar;
if (substr($v,0,1) == $filterVar) {
return $v;
}
}
$filterVar = 'a';
$newEntries = array_filter($entries,'filterFunction');
var_dump($newEntries);
Here's one way of generating filter functions using a closure.
function filter_factory($letter) {
return function ($input) use ($letter) {
return is_string($input) && $input[0] === $letter;
};
}
$entries = array('p01','p02','g01','g02','a001','a002');
$p_entries = array_filter($entries, filter_factory('p'));
This type of solution is much more intuitive and dynamic.
In this example, there are several types of solutions:
Search in the first letters
Sensitive to capital letters
is_array() so if it tends to avoid several errors
<?php
/*
* Search within an asociative array
* Examples:
* $array = array('1_p01','1_P02','2_g01','2_g02','3_a001','3_a002');
* find_in_array($array,'2');
* return: array( 2 => '2_g01',3 => '2_g02')
*
* find_in_array($array,'2',false);
* return: array( 1 => '1_P02')
*
* find_in_array($array,'P0',false,false);
* return: array( 0 => '1_p01',1 => '1_P02')
*
*/
function find_in_array($array, $find='', $FirstChar=true, $CaseInsensitive=true){
if ( is_array($array) ){
return preg_grep("/".($FirstChar ? '^':'')."{$find}/".($CaseInsensitive ? '':'i'), $array);
}
}
$array = array('1_p01','1_P02','2_g01','2_g02','3_a001','3_a002');
$a = find_in_array($array,'2');
var_export($a);
/*
Return:
array (
2 => '2_g01',
3 => '2_g02'
)
*/
$a = find_in_array($array,'P0',false);
var_export($a);
/*
Return:
array (
1 => '1_P02'
)
*/
$a = find_in_array($array,'P0',false,false);
var_export($a);
/*
Return:
array (
0 => '1_p01',
1 => '1_P02'
)
*/
I am trying to remove an element from a multidimentional array in PHP. Here is the code :
<?php
$tset = "ST3";
$gettc = "gettingtc1";
$getbid = "gettingbid1";
$getresultsid = "gettingresid1";
$users[$tset] = array();
$users[$tset][] = array( "testcase"=>"$gettc",
"buildid"=>"$getbid",
"resultsid"=>"$getresultsid"
);
$tset = "TEJ";
$gettc = "ggettingtc2";
$getbid = "gettingbid2";
$getresultsid = "gettingresid2";
$users[$tset][] = array( "testcase"=>"$gettc",
"buildid"=>"$getbid",
"resultsid"=>"$getresultsid"
);
$tset = "ST3";
$gettc = "ggettingtc12";
$getbid = "gettingbid13";
$getresultsid = "gettigresid14";
$users[$tset][] = array( "testcase"=>"$gettc",
"buildid"=>"$getbid",
"resultsid"=>"$getresultsid"
);
foreach ($users as $val => $yy)
{
echo "For $val the array is :";
foreach($yy as $uy)
{
echo $uy['testcase'].$uy['buildid'].$uy['resultsid'];
}
echo '<br>';
}
$ser = "gettingresid1";
$to = array_searchRecursive($ser,$users);
if($to <> 0)
{
print_r($to);
}
else
{
echo "not";
}
function array_searchRecursive( $needle, $haystack, $strict=true, $path=array() )
{
if( !is_array($haystack) ) {
return false;
}
foreach( $haystack as $key => $val ) {
if( is_array($val) && $subPath = array_searchRecursive($needle, $val, $strict, $path) ) {
$path = array_merge($path, array($key), $subPath);
return $path;
} elseif( (!$strict && $val == $needle) || ($strict && $val === $needle) ) {
$path[] = $key;
return $path;
}
}
return false;
}
?>
Where I am stuck is : $to holds the array that has my search element. But the results $to is holding should be removed from the original array $users.
Any help.
Thanks.
I think you want to use unset()
//assuming $to contains the key in $users that needs to be removed
//from the array
unset($users[$to]);
But as $to contains an array of keys to the element rather than a single key to the element, you would need to write your own functions to do what you want.
The function that does what you want is below, and will remove the element of the given array which has the address in $keys.
/**
* Removes the element with the keys in the array $keys
*
* #param haystack the array that contains the keys and values
* #param keys the array of keys that define the element to remove
* #return the new array
*/
function array_remove_bykeys( array $haystack, array $keys ){
//check if element couldn't be found
if ( empty($keys) ){
return $haystack;
}
$key = array_shift($keys);
if ( is_array($haystack[$key]) ){
$haystack[$key] = array_remove_bykeys($haystack[$key], $keys);
}else if ( isset($haystack[$key]) ){
unset($haystack[$key]);
}
return $haystack;
}
The other method would be to delete all the keys with the value you were looking for.
/**
* Removes all elements from that array that has the value $needle
* #param $haystack the origanal array
* #param $needle the value to search for
* #return a new array with the value removed
*/
function array_remove_recursive( array $haystack, $needle ){
foreach( $haystack as $key => $value ) {
if( is_array($value) ) {
$haystack[$key] = array_remove_recursive($value, $needle);
} else if ( $value === $needle ){
unset($haystack[$key]);
}
}
return $haystack;
}
For completeness (Although defiantly not recommended), here is a eval version:
$keys = array(...);//an array of keys
//$arr is the variable name that contains the value that you want to remove
eval ('unset($arr[\''.implode('\'][\'', $keys).'\']);');
Pass $users to array_searchRecursive by reference (add '&' to $haystack):
function array_searchRecursive( $needle, &$haystack, $strict=true, $path=array()
and then in array_searchRecursive, just before each return statement:
unset($haystack[$key]);