Can I make RecursiveDirectoryIterator skip unreadable directories? - php

foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(".")) as $file) {
echo "$file\n";
}
Is there any way for this code to not throw UnexpectedValueException "failed to open dir: Permission denied" whenever there is a unreadable subdirectory inside directory I attempt to list?
UPDATE
Converting foreach() to while() and explicitly calling Iterator::next() wrapped in try() catch {} doesn't help. This code:
$iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("."));
while($iter->valid()) {
$file = $iter->current();
echo "$file\n";
try {
$iter->next();
} catch(UnexpectedValueException $e) {
}
};
is an infinite loop if there is unreadable subdirectory.

Apparently you can pass $flags parameter to constructor. There's only one flag in the docs, but it does exactly what you want: catches exceptions during getChildren() calls and simply jumps to the next element.
Change your class creation code to
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator("."),
RecursiveIteratorIterator::LEAVES_ONLY,
RecursiveIteratorIterator::CATCH_GET_CHILD);
and it should work

You could do something like this :
class ReadableFilter extends RecursiveFilterIterator{
public function accept(){
return $this->current()->isReadable();
}
}
$filteredIterator = new RecursiveIteratorIterator(new ReadableFilter(new RecursiveDirectoryIterator(".")));
foreach ($filteredIterator as $file){
echo "$file\n";
}

Related

Check if the files have been uploaded to server with php slim 3

Hi have the following code in slim to save file
I want to make sure the files have been uploaded to the server and only then to return true. or false
how can I do that with Slim or PHP?
Result of file log always null for nonreason and the file are being uploaded
public function saveFiles(Array $files, $location) {
try
{
/** #var UploadedFileInterface $file */
foreach ($files as $file) {
$fileLog = $file->moveTo($location . DIRECTORY_SEPARATOR . $file->getFilename());
}
return true;
}
catch(\Exception $e) {
throw new Exception($e->getMessage());
According to slim implementaion of this PSR, it always throws exception if something went wrong while file is being uploaded.
I don't know whether you throw another Exception for a reason, but you can process it something like:
public function saveFiles(Array $files, $location) {
$result = true;
foreach ($files as $file) {
try {
$fileLog = $file->moveTo($location . DIRECTORY_SEPARATOR . $file->getFilename());
} catch(\Exception $e) {
// Exception on file uploading happened, but
// we still continue loading other files
$result = false;
// Or just `return false;` if you don't want
// to upload other files if exception happened
// return false;
}
}
return $result;
}
Of course, this method can be extended to collect exceptions' messages and return them.

Why not checking if template file really exists in ZF2?

In ZF 2.2.5 Zend\View\Renderer\PhpRenderer::render method there is an if statement that checks if template exists in template stack (line 497)
$this->__file = $this->resolver($this->__template);
if (!$this->__file) {
throw new Exception\RuntimeException(sprintf(
'%s: Unable to render template "%s"; resolver could not resolve to a file',
__METHOD__,
$this->__template
));
}
try {
ob_start();
include $this->__file;
$this->__content = ob_get_clean();
} catch (\Exception $ex) {
ob_end_clean();
throw $ex;
}
But it doesn't check if file really exists in file system. Which means that subsequent try { ... } catch(\Exception $ex) {...} block is useless, because include $this->__file; is uncatchable. So when I test my controllers I always get 200 response even if template file is missing and there is nothing but exception call stack on the screen. Shouldn't that if (!$this->__file) { ... } be rewritten to if (!is_file($this->__file)) { ... }?
Well, it's up to the resolver to perform these checks. See the following code taken from Zend\View\Resolver\TemplatePathStack:
foreach ($this->paths as $path) {
$file = new SplFileInfo($path . $name);
if ($file->isReadable()) {
// Found! Return it.
if (($filePath = $file->getRealPath()) === false && substr($path, 0, 7) === 'phar://') {
// Do not try to expand phar paths (realpath + phars == fail)
$filePath = $path . $name;
if (!file_exists($filePath)) {
break;
}
}
if ($this->useStreamWrapper()) {
// If using a stream wrapper, prepend the spec to the path
$filePath = 'zend.view://' . $filePath;
}
return $filePath;
}
}
Also note that include accepts more than is_file checks for. For instance, include also accepts stream wrappers.

Error Handling with files in PHP

Error Handling with files in PHP
$path = '/home/test/files/test.csv';
fopen($path, 'w')
Here I want add an error handling by throwing exceptions, on 'No file or directory is found' and 'No permission to create a file'.
I am using Zend Framework.
By using fopen with write mode, I can create a file. But how to handle it when corresponding folder is not there?
i.e if files folder is not present in root structure.
How to throw an exception when no permission is permitted for creating a file?
Something like this should get you started.
function createFile($filePath)
{
$basePath = dirname($filePath);
if (!is_dir($basePath)) {
throw new Exception($basePath.' is an existing directory');
}
if (!is_writeable($filePath) {
throw new Exception('can not write file to '.$filePath);
}
touch($filePath);
}
Then to call
try {
createFile('path/to/file.csv');
} catch(Exception $e) {
echo $e->getMessage();
}
I suggest, you take a look at this link: http://www.w3schools.com/php/php_ref_filesystem.asp
especially the methods file_exists and is_writable
Like this:
try
{
$path = '/home/test/files/test.csv';
fopen($path, 'w')
}
catch (Exception $e)
{
echo $e;
}
PHP will echo whatever error would arise there.
Though you can also use is_dir or is_writable functions to see if folder exists and has permission respectively:
is_dir(dirname($path)) or die('folder doesnt exist');
is_writable(dirname($path)) or die('folder doesnt have write permission set');
// your rest of the code here now...
But how to handle it when corresponding folder is not there?
When a folder does not exist .. try to create it!
$dir = dirname($file);
if (!is_dir($dir)) {
if (false === #mkdir($dir, 0777, true)) {
throw new \RuntimeException(sprintf('Unable to create the %s directory', $dir));
}
} elseif (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in the %s directory', $dir));
}
// ... using file_put_contents!

PHP recursive delete function gives warning message

My function cleanup looks like that.
function cleanUp($exdirs, $exfiles){
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('.'),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach($it as $entry) {
if ($entry->isDir() && !in_array($entry->getBasename(), $exdirs)) {
try {
rmdir($entry->getPathname());
}
catch (Exception $ex) {
// dir not empty
}
}
elseif (!in_array($entry->getFileName(), $exfiles)) {
unlink($entry->getPathname());
}
}
}
And calling this function like that
$excludeDirsNames = array('cgi-bin');
$excludeFileNames = array('ws.zip');
cleanUp($excludeDirsNames , $excludeFileNames);
Now the problem is i'm getting warning message. can not unlink cgi-bin on line unlink($entry->getPathname());
What's wrong with my function? How to fix that problem?
I am guessing that cgi-bin is a symlink and not a regular directory. That's why it's getting into the "unlink" section. The error message is probably due to permissions.
The fix, move 'cgi-bin' to the $excludeFileNames array.

How can I get around the lack of a finally block in PHP?

PHP prior to version 5.5 has no finally block - i.e., whereas in most sensible languages, you can do:
try {
//do something
} catch(Exception ex) {
//handle an error
} finally {
//clean up after yourself
}
PHP has no notion of a finally block.
Anyone have experience of solutions to this rather irritating hole in the language?
Solution, no. Irritating cumbersome workaround, yes:
$stored_exc = null;
try {
// Do stuff
} catch (Exception $exc) {
$stored_exc = $exc;
// Handle an error
}
// "Finally" here, clean up after yourself
if ($stored_exc) {
throw($stored_exc);
}
Yucky, but should work.
Please note: PHP 5.5 finally (ahem, sorry) added a finally block: https://wiki.php.net/rfc/finally (and it only took a few years... available in the 5.5 RC almost four years to the date since I posted this answer...)
The RAII idiom offers a code-level stand-in for a finally block. Create a class that holds callable(s). In the destuctor, call the callable(s).
class Finally {
# could instead hold a single block
public $blocks = array();
function __construct($block) {
if (is_callable($block)) {
$this->blocks = func_get_args();
} elseif (is_array($block)) {
$this->blocks = $block;
} else {
# TODO: handle type error
}
}
function __destruct() {
foreach ($this->blocks as $block) {
if (is_callable($block)) {
call_user_func($block);
} else {
# TODO: handle type error.
}
}
}
}
Coordination
Note that PHP doesn't have block scope for variables, so Finally won't kick in until the function exits or (in global scope) the shutdown sequence. For example, the following:
try {
echo "Creating global Finally.\n";
$finally = new Finally(function () {
echo "Global Finally finally run.\n";
});
throw new Exception;
} catch (Exception $exc) {}
class Foo {
function useTry() {
try {
$finally = new Finally(function () {
echo "Finally for method run.\n";
});
throw new Exception;
} catch (Exception $exc) {}
echo __METHOD__, " done.\n";
}
}
$foo = new Foo;
$foo->useTry();
echo "A whole bunch more work done by the script.\n";
will result in the output:
Creating global Finally.
Foo::useTry done.
Finally for method run.
A whole bunch more work done by the script.
Global Finally finally run.
$this
PHP 5.3 closures can't access $this (fixed in 5.4), so you'll need an extra variable to access instance members within some finally-blocks.
class Foo {
function useThis() {
$self = $this;
$finally = new Finally(
# if $self is used by reference, it can be set after creating the closure
function () use ($self) {
$self->frob();
},
# $this not used in a closure, so no need for $self
array($this, 'wibble')
);
/*...*/
}
function frob() {/*...*/}
function wibble() {/*...*/}
}
Private and Protected Fields
Arguably the biggest problem with this approach in PHP 5.3 is the finally-closure can't access private and protected fields of an object. Like accessing $this, this issue is resolved in PHP 5.4. For now, private and protected properties can be accessed using references, as Artefacto shows in his answer to a question on this very topic elsewhere on this site.
class Foo {
private $_property='valid';
public function method() {
$this->_property = 'invalid';
$_property =& $this->_property;
$finally = new Finally(function () use (&$_property) {
$_property = 'valid';
});
/* ... */
}
public function reportState() {
return $this->_property;
}
}
$f = new Foo;
$f->method();
echo $f->reportState(), "\n";
Private and protected methods can be accessed using reflection. You can actually use the same technique to access non-public properties, but references are simpler and more lightweight. In a comment on the PHP manual page for anonymous functions, Martin Partel gives an example of a FullAccessWrapper class that opens up non-public fields to public access. I won't reproduce it here (see the two previous links for that), but here is how you'd use it:
class Foo {
private $_property='valid';
public function method() {
$this->_property = 'invalid';
$self = new FullAccessWrapper($this);
$finally = new Finally(function () use (&$self) {
$self->_fixState();
});
/* ... */
}
public function reportState() {
return $this->_property;
}
protected function _fixState() {
$this->_property = 'valid';
}
}
$f = new Foo;
$f->method();
echo $f->reportState(), "\n";
try/finally
try blocks require at least one catch. If you only want try/finally, add a catch block that catches a non-Exception (PHP code can't throw anything not derived from Exception) or re-throw the caught exception. In the former case, I suggest catching StdClass as an idiom meaning "don't catch anything". In methods, catching the current class could also be used to mean "don't catch anything", but using StdClass is simpler and easier to find when searching files.
try {
$finally = new Finally(/*...*/);
/* ... */
} catch (StdClass $exc) {}
try {
$finally = new Finally(/*...*/);
/* ... */
} catch (RuntimeError $exc) {
throw $exc
}
Here is my solution to the lack of finally block. It not only provides a work around for the finally block, it also extends the try/catch to catch PHP errors (and fatal errors too). My solution looks like this (PHP 5.3):
_try(
//some piece of code that will be our try block
function() {
//this code is expected to throw exception or produce php error
},
//some (optional) piece of code that will be our catch block
function($exception) {
//the exception will be caught here
//php errors too will come here as ErrorException
},
//some (optional) piece of code that will be our finally block
function() {
//this code will execute after the catch block and even after fatal errors
}
);
You can download the solution with documentation and examples from git hub -
https://github.com/Perennials/travelsdk-core-php/tree/master/src/sys
As this is a language construct, you won't find an easy solution for this.
You can write a function and call it as the last line of your try block and last line before rethrowing the excepion in the try block.
Good books argues against using finally blocks for any other than freeing resource as you can not be sure it will execute if something nasty happens. Calling it an irritating hole is quite an overstatement.
Believe me, a hell lot of exceptionally good code is written in languages without finally block. :)
The point of finally is to execute no matter if the try block was successfull or not.
function _try(callable $try, callable $catch, callable $finally = null)
{
if (is_null($finally))
{
$finally = $catch;
$catch = null;
}
try
{
$return = $try();
}
catch (Exception $rethrow)
{
if (isset($catch))
{
try
{
$catch($rethrow);
$rethrow = null;
}
catch (Exception $rethrow) { }
}
}
$finally();
if (isset($rethrow))
{
throw $rethrow;
}
return $return;
}
Call using closures. Second parameter, $catch, is optional. Examples:
_try(function ()
{
// try
}, function ($ex)
{
// catch ($ex)
}, function ()
{
// finally
});
_try(function ()
{
// try
}, function ()
{
// finally
});
Properly handles exceptions everywhere:
$try: Exception will be passed to $catch. $catch will run first, then $finally. If there is no $catch, exception will be rethrown after running $finally.
$catch: $finally will execute immediately. Exception will be rethrown after $finally completes.
$finally: Exception will break down the call stack unimpeded. Any other exceptions scheduled for rethrow will be discarded.
None: Return value from $try will be returned.
If anyone is still keeping track of this question, you might be interested in checking out the (brand new) RFC for a finally language feature in the PHP wiki. The author already seems to have working patches, and I'm sure the proposal would benefit from other developers' feedback.
I just finished writing a more elegant Try Catch Finally class which may be of use to you. There are some drawbacks but they can be worked around.
https://gist.github.com/Zeronights/5518445

Categories