Blogs

Both Zend_Cache::_isReadable() and Zend_Loader::isReadable() code and performance could be improved using the new PHP 5.3.2 stream_resolve_include_path() function and removing the error suppression (@). Zend_Cache::_isReadable() can be particularly slow due to error suppression so

private static function _isReadable($filename)
{
    if (!$fh = @fopen($filename, 'r', true)) {
        return false;
    }
    @fclose($fh);
    return true;
}

first of all could be rewritten to:

private static function _isReadable($filename)
{
    return is_string(stream_resolve_include_path($filename));
}

or, for backward compatibility:

private static function _isReadable($filename)
{
    if (function_exists('stream_resolve_include_path')) {
        return is_string(stream_resolve_include_path($filename));
    }

    if (!$fh = @fopen($filename, 'r', true)) {
        return false;
    }
    @fclose($fh);
    return true;
}

Something similar applies to Zend_Loader

public static function isReadable($filename)
{
    // ADDED CODE

    if (function_exists('stream_resolve_include_path')) {
        return is_string(stream_resolve_include_path($filename));
    }
    
    // OLD CODE

    [....]

    foreach (self::explodeIncludePath() as $path) {
        if ($path == '.') {
            if (is_readable($filename)) {
                return true;
            }
            continue;
        }
        $file = $path . '/' . $filename;
        if (is_readable($file)) {
            return true;
        }
    }
    return false;
}

so that the foreach loop will be avoided with PHP 5.3.2.

Zend_Cache method comes from Zend_Loader (see #ZF-2891 for details) so it would make sense to extrapolate the code in a separate class, taking into consideration to use Zend_Loader code instead of the error suppression, something like this (comments removed for brevity):

class Zend_File
{
    public static function isReadable($filename)
    {
        if (function_exists('stream_resolve_include_path')) {
            return is_string(stream_resolve_include_path($filename));
        }

        if (is_readable($filename)) {
            return true;
        }

        if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'
            && preg_match('/^[a-z]:/i', $filename)
        ) {
            return false;
        }

        foreach (Zend_Application::getIncludePathArray() as $path) {
            if ($path == '.') {
                if (is_readable($filename)) {
                    return true;
                }
                continue;
            }
            $file = $path . '/' . $filename;
            if (is_readable($file)) {
                return true;
            }
        }
        return false;
    }
}

adding this to Zend_Application:

/**
 * explodeIncludePath() method renamed to getIncludePathArray()
 * Todo: Cache the result ?
 */
public static function getIncludePathArray($path = null)
{
    if (null === $path) {
        $path = get_include_path();
    }

    if (PATH_SEPARATOR == ':') {
        $paths = preg_split('#:(?!//)#', $path);
    } else {
        $paths = explode(PATH_SEPARATOR, $path);
    }
    return $paths;
}

where I suggest to rename explodeIncludePath() to getIncludePathArray() that sounds more appropriate. explodeIncludePath() should also be removed from Zend_Loader taking care to notice the users since it is a public method.

To avoid confusion with PHP is_readable() function, why not renaming isReadable() to isAccessible() deprecating the old methods with a trigger_error('...', E_USER_NOTICE) ?

In case you didn't know, during the last months Ibuildings has launched many challenges to PHP developers, rewarding the winners with iPads and tickets for the DPC 2010.

Unfortunately the contest is not for us, but a PHP challenge can't be refused, right?

The first challenge consisted on developing a script to calculate the shortest path through a list of towns, one of the TSP variants. Forgetting the problem complexity, that could be approached in many different ways with exact or approximate algorithms, dynamic programming, genetic algorithms, euristics, branch&bound etc., the challenge required to minimize time, memory, lines of code and complexity. You can find more details and an interesting reading on Andy Thompson blog.

The second challenge, just closed at the end of June, required to write a PHP class to cover all the tests of a PHPUnit class provided by Ibuildings, with the least number of rows (following best practices, not everything on a row). At the same time a much more interesting (to me) an unofficial challenge started on Twitter: writing the shortest solution in terms of bytes Laughing out loud.

Going straight to the point, skipping all the refactoring/compression stuff, these are two solutions I submitted plus one I just posted following some crazy comments to the Techportal blog post.

The "honest" one: 192 bytes

<?eval(str_replace(range(B,I),split(X,'De( $n)X;}E FX+self::FXfuncIXoperaIXH{returnHX($n)Xtion'),'class numbercruncher{E FaG+4CbG*3CcG/2*HCfG/2*9*HCgGDdH-DeH-HCdG?H*Dd(H-1):1CeG<2?H:BB;}}'));

This works out of the box on any system, without using any trick or assumption, the one I spent more time on. It would work also in the case that more tests are added. It's not listed on Ibuildings post because I sent also the following one, apparently it's the shortest honest solution.

The "cheating" one: 153 bytes

<?class NumberCruncher{function __call($a,$b){$t=debug_backtrace();$l=file($t[1][file]);preg_match('#([-.\d]+)\s*,#',$l[$t[1][line]-1],$r);return$r[1];}}

Just a dirty trick, load the solutions from the Unit test itself, the weakest point is the regular expression, fine tuned for the unit test source code (blank spaces included), that would fail simply modifying the unit test source code. Kudos to Arpad Ray who managed to squeeze out 20 more bytes with the same method, impressive!

The one with assumptions: 22 bytes

You should read the post on Ibuildings Techportal, you'll have some fun seeing how much effort PHP developers put on the matter! Since someone started making assumptions on the system, assuming it is a *nix one, that PHP can run system commands etc., I posted the following, the shortest so far, let's see if some shorter url comes up Wink

<?eval(`curl l0l.it`);

Look forward to the next challenge, we could start writing Zend Framework bots to run into an arena (the Ibuildings Arena ?)

Forcing a Mysql slave to delay seconds or minutes behind a master can be useful for many reasons:

- test your application to see how it reacts in case of a lagged replication
- release financial data after a period of validation
- build some sort of wayback machine
- protect against oops
etc.

moxi is a memcached proxy with several features which can help keep the memcached contract whole in complicated environments. It also brings several optimizations to memcached deployments, without requiring any changes to the application software using memcached.

"One of the key values at Facebook is to move fast. For the past six years, we have been able to accomplish a lot thanks to rapid pace of development that PHP offers. As a programming language, PHP is simple. Simple to learn, simple to write, simple to read, and simple to debug. We are able to get new engineers ramped up at Facebook a lot faster with PHP than with other languages, which allows us to innovate faster."

The idea of that talk is to go through the classes of vulnerabilities or security problems that you usually need to take care of yourself and look at the Zend Framework to check what internal protection ZF offers and how they are used and what problems you still need to solve on your own.

http://techportal.ibuildings.com/2009/10/13/secure-programming-with-the-...

Syndicate content
© 2010 Devis Lucato.