Skip to content

Instantly share code, notes, and snippets.

@psrpinto
Created July 7, 2015 02:14
Show Gist options
  • Save psrpinto/1fe7ff7b9336b197c0d8 to your computer and use it in GitHub Desktop.
Save psrpinto/1fe7ff7b9336b197c0d8 to your computer and use it in GitHub Desktop.
Support local filesystems with a large number of directories or files (using Flysystem)
<?php
namespace Acme\Adapter;
use League\Flysystem\Adapter\Local;
/**
* A local adapter that works around filesystems' limit of subdirectories in a
* directory.
*
* For files or directories in the root of the filesystem, we SHA1-hash their
* name and use the first 4 chars of the hash as four levels of subdirs. The file
* or directory is then placed inside the last level.
*
* Thus, a directory with name 'foo' will be interpreted as "0/b/e/e/foo", where
* "0bee" are the first four characters of sha1('foo')
*/
class LocalSpread extends Local
{
public function applyPathPrefix($path)
{
// Only apply the prefix if it's not already present
if (empty($path) || preg_match('/^([a-fA-F0-9]\/){4}/', $path)) {
return parent::applyPathPrefix($path);
}
// We're only interested in prefixing the first level, imediately under
// the filesystem root
$pos = strpos($path, DIRECTORY_SEPARATOR);
if (false === $pos) {
$prefix = $this->getPrefix($path);
} else {
$prefix = $this->getPrefix(substr($path, 0, $pos));
}
return parent::applyPathPrefix($prefix.DIRECTORY_SEPARATOR.$path);
}
private function getPrefix($path)
{
return implode(DIRECTORY_SEPARATOR, str_split(substr(hash('sha1', $path), 0, 4)));
}
}
<?php
namespace Acme\Tests\Adapter;
use Memeoirs\StorageBundle\Adapter\LocalSpread;
class LocalSpreadTest extends \PHPUnit_Framework_TestCase
{
const ROOT = '/tmp';
public function setUp()
{
$this->adapter = new LocalSpread(self::ROOT);
}
public function testApplyPathPrefix()
{
$this->doTestApplyPathPrefix('', '');
$this->doTestApplyPathPrefix('foo', '0/b/e/e/foo');
$this->doTestApplyPathPrefix('foo/bar', '0/b/e/e/foo/bar');
$this->doTestApplyPathPrefix('0/b/e/e/foo/bar', '0/b/e/e/foo/bar');
}
private function doTestApplyPathPrefix($path, $realPath)
{
$this->assertEquals(
$this->adapter->applyPathPrefix($path),
self::ROOT.DIRECTORY_SEPARATOR.$realPath
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment