Is it possible to check how many items are within $_FILES[] using some sort of length() or size() ?
It's a normal array besides the fact that it's superglobal - simply use count($_FILES).
To count the successfully uploaded files, you could do the following in PHP5.3:
$successCount = array_reduce($_FILES, function($val, $file) {
if($file['error'] == UPLOAD_ERR_OK) return $val + 1;
return $val;
}, 0);
In older PHP versions the easiest way (I consider string function names for callbacks ugly) would be using a simple loop:
$count = 0;
foreach($_FILES as $file) {
if($file['error'] == UPLOAD_ERR_OK) $count++;
}
The count() function does that: http://php.net/manual/en/function.count.php
$c = count($_FILES);
there are 2 ways in naming fields for the upload.
While filename[] will make this array messy, filename1, filename2 etc will make $_FILES array behave as you expected and count($_FILES) will return number of input fields
If you don't know array structure, you should use print_r($_FILES) to see it first and then decide, what you want to count.
Also note that array name is $_FILES, not $_FILES[] as you mentioned. It's operator, not array name.
Related
I'm having this problem.
Let's assume that I have a series of folders, inside of these folders, they have have a unlimited supply of sub folders and you can have an unlimited supply of files within this.
Using Recusion, I am trying to get the number of all of the files that exist within the sub directories, as well as this, get the total number of files from the sub sub directly.
I am using the following:
$SubSectionTotalCount = 0;
$SubSectionComplete = 0;
function GetStats($child, $groups, $progress, $resCount, $complete)
{
foreach($child->children as $childElement)
{
if($childElement->resources != null)
{
foreach($childElement->resources->groups as $groupss)
{
if(Check($groupss->id, $groups))
{
if(array_key_exists($childElement->parent_id, $progress))
{
if(array_key_exists($childElement->resources->id, $progress[$childElement->parent_id]['tasks']))
{
$complete++;
}
}
$resCount++;
var_dump($resCount);
}
}
}
GetStats($childElement, $groups, $progress, $resCount, $complete);
}
}
I currently have 4 sections (which therefore resCount should print 4) but instead, I am getting:
int 1
int 2
int 3
int 2
If I don't increment the variables, and just var_dump("getting here") I get the following:
Getting here
Getting here
Getting here
Getting here
So the recursion is working, however I don't understand why incrementing is not producing the desired output?
I'm not sure I'm reading you code correctly, but to me it seems like you're trying to modify a value inside a function, but then the value is not returned outside of it.
Basically you should pass your parameter by reference (using &) instead of by value (which is what you're doing here), or a better option would be to refactor your code so that your function returns a value instead of trying to change one. That seems to be the problem to me.
There are two commonly used methods for recursively walking directories in PHP. Primarily using either glob or RecursiveDirectoryIterator / RecursiveIteratorIterator.
Between the two, the iterator method is a more direct representation of file traversing. Try to get used to using iterators if you can.
Common Recursive Glob Method ( PHP 4+)
function getAllFiles($pattern)
{
$files = glob($pattern, 0);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir)
$files = array_merge($files, getAllFiles($dir.'/'.basename($pattern), 0));
return $files;
}
$numFiles = count( getAllFiles('*') );
Common Recursive Iterator Method (PHP 5+)
$dirIterator = new RecursiveDirectoryIterator('/path');
$iterator = new RecursiveIteratorIterator(
$dirIterator,
RecursiveIteratorIterator::SELF_FIRST
);
$numFiles=0;
foreach ($iterator as $file) ++$numFiles; //If you need to access files also.
$numFiles=iterator_count($iterator); //If you only want the count
When dealing with arrays I am forced to add a bunch of repetitive code to handle arrays with one child versus multiple:
//If more than one step, process each step, elcse processs single
if(!array_key_exists('command',$pullcase['steps']['step'])) {
foreach($pullcase['steps']['step'] as $step) {
$command=$step['command'];
$parameter=$step['parameter'];
if(isset($step['value'])){
$value = $step['value'];
$this->runCommands($command,$parameter,$value);
} else {
$this->runCommands($command,$parameter);
}
}
} else {
$command = $pullcase['steps']['step']['command'];
$parameter = $pullcase['steps']['step']['parameter'];
if(isset($pullcase['steps']['step']['value'])){
$value = $pullcase['steps']['step']['value'];
$this->runCommands($command,$parameter,$value);
}
else { $this->runCommands($command,$parameter); }
}
As you can see, I'm having to duplicate my efforts depending on if there is a single item in an array versus multiple:
$pullcase['steps']['step'][0]['command']
vs
$pullcase['steps']['step']['command']
How can I simplify this code so that I can use a single variable for all instances?
If you control the creation of the array, make step an array of one even if there is only one so you always have an array. Is that possible?
You either have a step array [step][0][command] or you have a single step [step][command]. So when you create the array instead of [step][command] make it [step][0][command] etc. Standard way of doing it, problem solved as you only need the foreach.
If you can't do it at array creation then consider doing it before the loop:
if(is_array($pullcase['steps']['step'])) {
$steps = $pullcase['steps']['step'];
} else {
$steps[] = $pullcase['steps']['step'];
}
foreach($steps as $step) {
$value = isset($step['value']) ? $step['value'] : null;
$this->runCommands($step['command'], $step['parameter'], $value);
}
Also, if runCommands() can detect a empty argument, then an alternative to the if/else for the function call is used above.
The following may help. It doesn't do much but call the function "runcommands" on a value if the key is 'command'. I am using it to show how you can use array_walk_recursive to possibly solve your problem.
First, you need the function to use:
function runcommandswhencommand($value, $key)
{
if($key == 'command') runcommands($value);
}
Now, you can use the recursive walk on your array:
array_walk_recursive($pullcase, 'runcommandswhencommand');
With this, whenever the key is 'command', the value of that index will be used in the parameter of the function runcommands().
I have an array with numerous dimensions, and I want to test for the existence of a cell.
The below cascaded approach, will be for sure a safe way to do it:
if (array_key_exists($arr, 'dim1Key'))
if (array_key_exists($arr['dim1Key'], 'dim2Key'))
if (array_key_exists($arr['dim1Key']['dim2Key'], 'dim3Key'))
echo "cell exists";
But is there a simpler way?
I'll go into more details about this:
Can I perform this check in one single statement?
Do I have to use array_key_exist or can I use something like isset? When do I use each and why?
isset() is the cannonical method of testing, even for multidimensional arrays. Unless you need to know exactly which dimension is missing, then something like
isset($arr[1][2][3])
is perfectly acceptable, even if the [1] and [2] elements aren't there (3 can't exist unless 1 and 2 are there).
However, if you have
$arr['a'] = null;
then
isset($arr['a']); // false
array_key_exists('a', $arr); // true
comment followup:
Maybe this analogy will help. Think of a PHP variable (an actual variable, an array element, etc...) as a cardboard box:
isset() looks inside the box and figures out if the box's contents can be typecast to something that's "not null". It doesn't care if the box exists or not - it only cares about the box's contents. If the box doesn't exist, then it obviously can't contain anything.
array_key_exists() checks if the box itself exists or not. The contents of the box are irrelevant, it's checking for traces of cardboard.
I was having the same problem, except i needed it for some Drupal stuff. I also needed to check if objects contained items as well as arrays. Here's the code I made, its a recursive search that looks to see if objects contain the value as well as arrays. Thought someone might find it useful.
function recursiveIsset($variable, $checkArray, $i=0) {
$new_var = null;
if(is_array($variable) && array_key_exists($checkArray[$i], $variable))
$new_var = $variable[$checkArray[$i]];
else if(is_object($variable) && array_key_exists($checkArray[$i], $variable))
$new_var = $variable->$checkArray[$i];
if(!isset($new_var))
return false;
else if(count($checkArray) > $i + 1)
return recursiveIsset($new_var, $checkArray, $i+1);
else
return $new_var;
}
Use: For instance
recursiveIsset($variables, array('content', 'body', '#object', 'body', 'und'))
In my case in drupal this ment for me that the following variable existed
$variables['content']['body']['#object']->body['und']
due note that just because '#object' is called object does not mean that it is. My recursive search also would return true if this location existed
$variables->content->body['#object']->body['und']
For a fast one liner you can use has method from this array library:
Arr::has('dim1Key.dim2Key.dim3Key')
Big benefit is that you can use dot notation to specify array keys which makes things simpler and more elegant.
Also, this method will work as expected for null value because it internally uses array_key_exists.
If you want to check $arr['dim1Key']['dim2Key']['dim3Key'], to be safe you need to check if all arrays exist before dim3Key. Then you can use array_key_exists.
So yes, there is a simpler way using one single if statement like the following:
if (isset($arr['dim1Key']['dim2Key']) &&
array_key_exists('dim3Key', $arr['dim1Key']['dim2Key'])) ...
I prefer creating a helper function like the following:
function my_isset_multi( $arr,$keys ){
foreach( $keys as $key ){
if( !isset( $arr[$key] ) ){
return false;
}
$arr = $arr[$key];
}
return $arr;
}
Then in my code, I first check the array using the function above, and if it doesn't return false, it will return the array itself.
Imagine you have this kind of array:
$arr = array( 'sample-1' => 'value-1','sample-2' => 'value-2','sample-3' => 'value-3' );
You can write something like this:
$arr = my_isset_multi( $arr,array( 'sample-1','sample-2','sample-3' ) );
if( $arr ){
//You can use the variable $arr without problems
}
The function my_isset_multi will check for every level of the array, and if a key is not set, it will return false.
We gave a given array which can be in 4 states.
array has values that are:
only arrays
only non-arrays
both array and non array
array has no values
Considering than an array-key can only be a numerical or string value (and not an array), I suppose you want to know about array-values ?
If so, you'll have to loop over your array, testing, for each element, if it's an array or not, keeping track of what's been found -- see the is_array function, about that.
Then, when you've tested all elements, you'll have to test if you found arrays, and/or non-array.
Something like this, I suppose, might do the trick :
$has_array = false;
$has_non_array = false;
foreach ($your_array as $element) {
if (is_array($element)) {
$has_array = true;
} else {
$has_non_array = true;
}
}
if ($has_array && $has_non_array) {
// both
} else {
if ($has_array) {
// only arrays
} else {
// only non-array
}
}
(Not tested, but the idea should be there)
This portion of code should work for the three first points you asked for.
To test for "array has no value", The fastest way is to use the empty() language construct before the loop -- and only do the loop if the array is not empty, to avoid any error.
You could also count the number of elements in the array, using the count() function, and test if it's equal to 0, BTW.
Some precalculation:
function isArray($reducedValue, $currentValue) {
// boolean value is converted to 0 or 1
return $reducedValue + is_array($currentValue);
}
$number_of_arrays = array_reduce($array, 'isArray', 0);
Then the different states can be evaluated as follows:
only arrays
count($array) == $number_of_arrays
only non-arrays
$number_of_arrays == 0
both array and non array keys
count($array) != $number_of_arrays
array has no keys
empty($array);
So you just need to write a function that returns the appropriate state.
Reference: in_array, array_reduce, empty
I'd like to check if there is a value on an array like this:
function check_value_new ($list, $message) {
foreach ($list as $current) {
if ($current == $message) return true;
}
return false;
}
function check_value_old ($list, $message) {
for ($i = 0; $i < count ($status_list); $i ++) {
if ($status_list[$i] == $$message) return true;
}
return false;
}
$arr = array ("hello", "good bye", "ciao", "buenas dias", "bon jour");
check_value_old ($arr, "buenas dias"); // works but it isn't the best
check_value_new ($arr, "buenas dias"); // argument error, where I'm wrong?
I've read the check_value_new method is a better way to work with arrays, but I'm not used to work with it, how I should fix it?
PHP offers a function called in_array that checks if a value exists in a given array.
You can change your check_value_new function to include this:
function check_value_new ($list, $message) {
foreach ($list as $current) {
if (in_array($message, $current)) {
return true;
}
return false;
}
If you'd like to, you could also make the function work without the foreach loop, like so
function check_value_new ($list, $message) {
// returns true if found, else returns false.
return in_array($message, $list);
}
The reasons that your check_value_old() function breaks is because you have a typo in your loop's second parameter. $status_list is not one of the variables passed into your function and it is not declared anywhere before it is used. You merely need to use $list instead. It is also not necessary to call count() on every iteration -- since that value never changes in the loop, just call it once before the loop and use that value in the second parameter.
As for deciding how to loop over array values, there is no reason to reinvent a native function call. in_array() was already designed and optimized to search linear values in an array and return true as soon as it finds a match; otherwise it returns false.
I don't know what #AnthonyForloney is doing by writing in_array() inside of a foreach() loop. Not only will the snippet break because there aren't enough curly braces, the input array does not have two levels of data, so in_array() will choke when it receives $current which is a string (not the expected array).
Ultimately, my advice is: Only write your own custom function when there isn't a native function to suit your needs. Throw away both of the manual looping ideas and only call:
$arr = ["hello", "good bye", "ciao", "buenas dias", "bon jour"];
var_export(in_array("buenas dias", $arr));
One final insight that I'd like to provide is regarding microoptimization. If you are planning to check the existence of a unique value in a "very large" array, or if you are going to be making thousands of searches on the same array, then it would be more efficient to set up your array in a "flipped" orientation and call isset() or array_key_exists(). isset()/array_key_exists() will always outperform in_array() or array_search() because of the way that php handles arrays as "hash maps". More reading here.