Zend Cloud + WebDav + Яндекс.Диск

// Май 10th, 2012 // Highload, Zend Framework

В нашем проекте встала задача выделения отдельного сервера под хранение и отдачу статических данных (картинок, музыки и видео). В этом посте я расскажу о том, как я писал свой адаптер хранения на Zend SimpleCloud API. Основаня фишка в том, что он стандартизирован и при желании его можно будет поменять на Amazon S3 не переписывая код. Также данный клиент поддерживает работу с новым сервисом от Яндекса — Яндекс.Диск.

Задача

Итак, проблема состояла в том, что наше веб-сервер занимался всем что угодно. И генерировал странички пользователям, и отдавал статику (включая видео, музыку и картинки), и ресайзил изображения. Было принято решения сделать наконец из веб-сервера веб-сервер, а именно вынести все эти операции на job-сервер, а сам статичный контент на сервер статики.

Архитектура

Сервера статики располагются отдельно, клиенты коннектятся к ним по HTTP протоколу и забирают картинки как обычно. Заливку картинок осуществляет либо само веб-приложение по протоколу WebDav либо демон, который выполняет задачи из очереди. В качестве протокола общения с серверами статики будем использовать WebDav, в качестве сервера очередей — Gearman.

Конфигурируем nginx

Nginx из deb-пакетов (который есть в репозитариях) нам не подойдёт, т.к. надо установить его вместе с модулем http_dav_module. Скачиваем, компилируем и устанавливаем сервер с требуемым модулем:

wget nginx.org/download/nginx-1.1.1.tar.gz
tar -xvf nginx-1.1.1.tar.gz
cd nginx-1.1.1
git clone https://github.com/arut/nginx-dav-ext-module.git ./dav-ext
./configure --sbin-path=/usr/sbin --conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--http-log-path=/var/log/nginx/access.log \
--http-client-body-temp-path=/var/lib/nginx/body \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-http_dav_module --add-module=./dav-ext

Обращаем внимание на строчки:
adding module in ./dav-ext
+ ngx_http_dav_ext_module was configured

make

Дальше по идее надо бы использовать make install, но мы не будем этого делать, чтобы не замусоривать систему. Надо убедиться, что у нас удалён старый nginx И поставить утилиту checkinstall, которая сделает нам deb-пакет и поставит его.

sudo apt-get remove nginx
sudo apt-get install checkinstall
sudo checkinstall

Дальше надо сконфигурировать nginx, я просто приведу свой конфиг.

server {
# Порт, принимаемые HOST и путь к сайту
listen 80;
server_name www.tok tok webdav.thankyou.ru;
set $root_path "/home/netandreus/web";

# Запрос статики с сервера статики
location / {

root $root_path;
index index.htm index.html index.php;
client_max_body_size 20m;
# client_body_temp_path /usr/local/nginx/html/;
dav_methods PUT DELETE MKCOL COPY MOVE;
dav_ext_methods PROPFIND OPTIONS;
create_full_put_path on; #при отсутствии вложенных папок, при включенной директиве, nginx автоматически создаст иерархию
dav_access user:rw group:r all:r; #права на файлы
autoindex on;
if ($request_method ~* GET) {
error_page 404 = @main_frontend;
}
limit_except GET {
allow all;
}
}

# Основной сервер
location @main_frontend {
proxy_pass http://site.ru;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
resolver 8.8.8.8;
}
}

Отлично, теперь можем побаловаться с ним. Единственный момент, nginx не поддерживает запрос OPTIONS+PROPFIND, поэтому подключить обычный WebDav клиент к нему не получитсяб но если вы скомпили его с nginx-dav-ext-module, то можете подконнектиться к нему любым клиентом. Например я проверял в Ubuntu с помощью Nautilus.

Чтобы работать с ним из PHP я разработал специальный адаптер ZendExtra_Cloud_SimpleStorage_Adapter_WebDav. Самое интересное, что его можно подключить к Zend_Cloud и потом при необходимости перейти на другое хранилище (например Amazon S3 без переписывания кода). Стандарты рулят! :-)

Итак вот список реализованных команд WebDav: PUT DELETE MKCOL COPY MOVE

А вот списко реализованный функций со стороны Zend: fetchItem(), storeItem(), deleteItem(), copyItem(), moveItem(), renameItem(), listItems() + дополнение в виде createFolder()

ZendExtra_Cloud_SimpleStorage_Adapter_WebDav.php

<?php
require_once 'Zend/Cloud/StorageService/Adapter.php';
require_once 'Zend/Cloud/StorageService/Exception.php';

/**
 * WebDav adapter for unstructured cloud storage.
 *
 * @category   ZendExtra
 * @package    ZendExtra_Cloud
 * @subpackage StorageService
 * @copyright  Copyright (c) 2012 Tokarchuk Andrey. (http://tokarchuk.ru)
 *
 * Examples:
 * =========
 * // Init storage
 * / ** @var ZendExtra_Cloud_StorageService_Adapter_WebDav $storage ** /
 * $storage = Zend_Cloud_StorageService_Factory::getAdapter(array(
 *    Zend_Cloud_StorageService_Factory::STORAGE_ADAPTER_KEY => 'ZendExtra_Cloud_StorageService_Adapter_WebDav',
 *   ZendExtra_Cloud_StorageService_Adapter_WebDav::SERVERS_KEY   => array(
 *       'static1.site.ru' => array('host' => '1.2.3.4', 'port' => '80')
 *   ),
 *    ZendExtra_Cloud_StorageService_Adapter_WebDav::DEFAULT_SERVER_KEY => 'static1.site.ru'
 * ));
 * // Fetch item
 * $storage->fetchItem('/upload/news/c3500cc0c4892f3eda2ef3876af567dd.png');
 * // Store Item
 * $data = file_get_contents(ROOT_PATH. '/utils/upload_test.txt');
 * $storage->storeItem('/upload/upload_test.txt', $data);
 * // Delete item
 * $storage->deleteItem('/upload/upload_test.txt');
 * // Copy item (first - without loading item toi client, second - with it)
 * $storage->copyItem('/upload/upload_test.txt', '/upload/upload_test2.txt');
 * $storage->copyItem('/upload/upload_test.txt', '/upload/upload_test2.txt', array('native' => false));
 * // Move item (first - without loading item toi client, second - with it)
 * $storage->moveItem('/upload/upload_test.txt', '/upload/upload_test3.txt');
 * $storage->moveItem('/upload/upload_test3.txt', '/upload/upload_test.txt', array('native' => false));
 * // Rename item (first - without loading item toi client, second - with it)
 * $storage->renameItem('/upload/upload_test.txt', 'upload_test2.txt');
 * $storage->renameItem('/upload/upload_test2.txt', 'upload_test.txt', array('native' => false));
 * // Directory listing (if in nginx allow)
 * var_dump($storage->listItems('/upload/'));
 *
 * Yandex.disk exapmle:
 * ====================
 * $storage = Zend_Cloud_StorageService_Factory::getAdapter(array(
 *    Zend_Cloud_StorageService_Factory::STORAGE_ADAPTER_KEY => 'ZendExtra_Cloud_StorageService_Adapter_WebDav',
 *   ZendExtra_Cloud_StorageService_Adapter_WebDav::SERVERS_KEY   => array(
 *       'static1.site.ru' => array('host' => 'webdav.yandex.ru', 'port' => '80', 'protocol' => 'https')
 *   ),
 *    ZendExtra_Cloud_StorageService_Adapter_WebDav::DEFAULT_SERVER_KEY => 'static1.site.ru'
 * ));
 * $files = $storage->listItems('/upload');
 */
class ZendExtra_Cloud_StorageService_Adapter_WebDav
    implements Zend_Cloud_StorageService_Adapter
{

    /*
    * Options array keys for the WebDav adapter.
    */
    const SERVERS_KEY        = 'servers';
    const DEFAULT_SERVER_KEY = 'defaultServerKey';

    /**
     * WebDav service instance.
     * @var Zend_Http_Client
     */
    protected $_client = NULL;
    protected $_servers = array();
    protected $_defaultServerKey = NULL;
    protected $_options = array();

    /**
     * WebDav commands
     * @var array
     */
    protected $_webDavCommands = array('GET', 'POST', 'PUT', 'DELETE', 'MKCOL', 'COPY', 'MOVE', 'PROPFIND', 'PROPPATCH', 'LOCK', 'UNLOCK', 'OPTIONS');

    /*
     * Constructor
     *
     * @param  array|Zend_Config $options
     * @return void
     */
    public function __construct($options = array())
    {
        if ($options instanceof Zend_Config) {
            $options = $options->toArray();
        }

        if (!is_array($options)) {
            throw new Zend_Cloud_StorageService_Exception('Invalid options provided');
        }
        if (isset($options[self::DEFAULT_SERVER_KEY])) {
            $this->_defaultServerKey = $options[self::DEFAULT_SERVER_KEY];
        }
        if (isset($options[self::SERVERS_KEY])) {
            $this->_servers = $options[self::SERVERS_KEY];
        }
        $this->_options = $options;
    }

    /**
     * Execute WebDav command on server and returns
     * responce object
     * @param $path
     * @param $command
     * @param array $options
     * @return Zend_Http_Response
     */
    public function command($path, $command, $options = array())
    {
        if(!in_array($command, $this->_webDavCommands))
            throw new Zend_Cloud_Exception('Unknown webdav command', 500);
        $path = $this->_getFullPath($path, array());
        $client = $this->getClient()->setUri($path);
        if($options['auth'] && count($options == 3) && $options['auth']['username'] && $options['auth']['password'] && $options['auth']['type'])
            $client->setAuth($options['auth']['username'], $options['auth']['password'], $options['auth']['type']);
        if($options['data'] && $options['mimeType'])
            $client->setRawData($options['data'], $options['mimeType']);
        if($options['headers'])
            $client->setHeaders($options['headers']);
        $responce = $client->request($command);
        return $responce;
    }

    /*
     * Get an item from the storage service.
     *
     * @param  string $path
     * @param  array $options
     * @return string
     */
    public function fetchItem($path, $options = array())
    {
        // Simple mode (not a webdav-command)
        if($options['simple'] == true) {
            $path = $this->_getFullPath($path, array());
            $item = file_get_contents($path);
            return $item;
        }

        // True webdav mode
        $response = $this->command($path, 'GET');
        $headers = $response->getHeaders();
        $item = $response->getBody();
        return $item;
    }

    /**
     * Store an item in the storage service.
     *
     * WARNING: This operation overwrites any item that is located at
     * $destinationPath.
     *
     * @TODO Support streams
     *
     * @param string $destinationPath
     * @param string|resource $data
     * @param  array $options
     * @return void
     */
    public function storeItem($destinationPath, $data, $options = array())
    {
        // Detect a mime-type
        if(!array_key_exists('mimeType', $options)) {
            $tmp = explode("/", $destinationPath);
            $filename = $tmp[count($tmp)-1];
            $options['filename'] = $filename;
            $tmp = explode(".", $filename);
            $extension = $tmp[count($tmp)-1];
            $options['mimeType'] = self::getMimeType($extension);
        }
        if(empty($options['mimeType']))
            throw new Zend_Cloud_StorageService_Exception('Can not store file without mime-type provided. Autodetermination of mime type failed.');
        if(!array_key_exists('filename', $options)) {
            $tmp = explode("/", $destinationPath);
            $options['filename'] = $tmp[count($tmp)-1];
        }
        $this->command($destinationPath, 'PUT', array('data' => $data, 'mimeType' => $options['mimeType']));
        /*
        $path = $this->_getFullPath($destinationPath);
        $client = $this->getClient()->setUri($path);
        $client->setRawData($data, $options['mimeType']);
        $client->request('PUT');
        */
    }

    /**
     * Delete an item in the storage service.
     *
     * @param  string $path
     * @param  array $options
     * @return void
     */
    public function deleteItem($path, $options = array())
    {
        if(empty($path))
            return false;
        try {
            $this->command($path, 'DELETE');
            /*
            $path = $this->_getFullPath($path);
            $client = $this->getClient()->resetParameters()->setUri($path);
            $client->request('DELETE');
            */
        } catch (Exception  $e) {
            throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$e->getMessage(), $e->getCode(), $e);
        }
    }

    /*
     * Copy an item in the storage service to a given path.
     *
     * WARNING: This operation is *very* expensive for services that do not
     * support copying an item natively.
     *
     * @TODO Support streams for those services that don't support natively
     *
     * @param  string $sourcePath
     * @param  string $destination path
     * @param  array $options
     * @params bool $native Use or not WebDav COPY
     * @return void
     */
    public function copyItem($sourcePath, $destinationPath, $options = array())
    {
        if(!array_key_exists('native', $options))
            $options['native'] = true;
        $path = $this->_getFullPath($sourcePath);

        if($options['native']) {
            $this->command($sourcePath, 'COPY', array('headers' => array('Destination'=>$destinationPath)));
            /*
            $client = $this->getClient()->setUri($path)->setHeaders(array('Destination'=>$destinationPath));
            $client->request('COPY');
            */
        } else {
            $data = $this->fetchItem($sourcePath);
            $this->storeItem($destinationPath, $data);
        }
    }

    /*
     * Move an item in the storage service to a given path.
     *
     * @TODO Support streams for those services that don't support natively
     *
     * @param  string $sourcePath
     * @param  string $destination path
     * @param  array $options
     * @return void
     */
    public function moveItem($sourcePath, $destinationPath, $options = array())
    {
        if(!array_key_exists('native', $options))
            $options['native'] = true;

        if($options['native']) {
            $this->command($sourcePath, 'MOVE', array('headers' => array('Destination'=>$destinationPath)));
            /*
            $path = $this->_getFullPath($sourcePath);
            $client = $this->getClient()->setUri($path)->setHeaders(array('Destination'=>$destinationPath));
            $client->request('MOVE');
            */
        } else {
            $data = $this->fetchItem($sourcePath);
            $this->storeItem($destinationPath, $data);
            $this->deleteItem($sourcePath);
        }
    }

    /**
     * Rename an item in the storage service to a given name.
     *
     *
     * @param  string $path
     * @param  string $name
     * @param  array $options
     * @return void
     */
    public function renameItem($path, $name, $options = array())
    {
        if(!array_key_exists('native', $options))
            $options['native'] = true;
        $tmp = explode("/", $path);
        $oldName = $tmp[count($tmp)-1];
        $destinationPath = str_replace($oldName, $name, $path);
        $this->moveItem($path, $destinationPath, $options);
    }

    /*
     * Creates a folder by WebDav
     * @param $path
     */
    public function createFolder($destinationPath) {
        $lastCharacter = $destinationPath[strlen($destinationPath)-1];
        if($lastCharacter != "/")
            $destinationPath .= "/";
        $path = $this->_getFullPath($destinationPath);
        $client = $this->getClient()->setUri($path);
        $client->request('MKCOL');
    }

    /**
     * List items in the given directory in the storage service
     *
     * The $path must be a directory
     * Supports nginx with directory listing enable
     *
     * @param  string $path Must be a directory
     * @param  array $options
     * @return array A list of item names
     */
    public function listItems($path, $options = null)
    {
        if($options['mode'] == "get") {
            $content = $this->_listByGet($path, $options);
        } else {
            $content = $this->_listByPropfind($path, $options);
        }
        return $content;
    }

    protected function _listByGet($path, $options = null)
    {
        try {
            $path = $this->_getFullPath($path);
            $html = file_get_contents($path);
            $dom = new Zend_Dom_Query($html);
            $result = $dom->query('html body pre a');
            $content = array();
            foreach($result as $element) {
                $text = $element->firstChild->wholeText; // $element->getAttribute('href')
                if($text != "../")
                    $content[] = str_replace("/", "", $text);
            }
            return $content;
        } catch (Exception $e) {
            throw new Zend_Cloud_StorageService_Exception('Directory listing fails.');
        }
    }

    /**
     * Listing directory using PROPFIND command.
     * @param $path
     * @param array $options
     * @return array
     * @throws Zend_Cloud_Exception
     */
    protected function _listByPropfind($path, $options = array())
    {
        $xml = '<?xml version="1.0" encoding="utf-8" ?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>';
        $response = $this->command($path, 'PROPFIND', array(
            'data' => $xml,
            'mimeType' => 'text/xml',
            'headers' => array(
                'Content-Type' => 'text/xml; charset="utf-8"',
                'Depth' => 1,
                'Content-Length' => strlen($xml)
            )
        ));

        if(empty($response))
            throw new Zend_Cloud_Exception('Empty response on propfind command', 500);
        $xml = $response->getBody();
        $dom = new Zend_Dom_Query($xml);
        $result = $dom->query('d:multistatus d:response d:href');
        $content = array();
        foreach($result as $element) {
            $text = $element->firstChild->wholeText; // $element->getAttribute('href')
            if($text != "../" && $text != $path && $text != $path.'/')
                $content[] = str_replace("/", "", $text);
        }
        return $content;
    }

    /**
     * Get a key/value array of metadata for the given path.
     *
     * @param  string $path
     * @param  array $options
     * @return array
     */
    public function fetchMetadata($path, $options = array())
    {
        require_once 'Zend/Cloud/OperationNotAvailableException.php';
        throw new Zend_Cloud_OperationNotAvailableException('Fetching metadata not implemented');
    }

    /**
     * Tests if file exists in storage
     * @param $path
     * @return bool
     */
    public function isItemExists($path)
    {
        $xml = '';
        $response = $this->command($path, 'PROPFIND', array(
            'data' => $xml,
            'mimeType' => 'text/xml',
            'headers' => array(
                'Content-Type' => 'text/xml; charset="utf-8"',
                'Depth' => 1,
                'Content-Length' => strlen($xml)
            )
        ));
        $xml = $response->getBody();
        $dom = new Zend_Dom_Query($xml);
        $result = $dom->query('D:status');
        foreach($result as $element) {
            $text = $element->firstChild->wholeText;
        }
        return (strpos($text, ' 200 OK') !== FALSE)? true : false;
    }

    /*
     * Store a key/value array of metadata at the given path.
     * WARNING: This operation overwrites any metadata that is located at
     * $destinationPath.
     *
     * @param  string $destinationPath
     * @param  array $options
     * @return void
     */
    public function storeMetadata($destinationPath, $metadata, $options = array())
    {
        require_once 'Zend/Cloud/OperationNotAvailableException.php';
        throw new Zend_Cloud_OperationNotAvailableException('Storing metadata not implemented');
    }

    /*
     * Delete a key/value array of metadata at the given path.
     *
     * @param  string $path
     * @param  array $options
     * @return void
     */
    public function deleteMetadata($path)
    {
        require_once 'Zend/Cloud/OperationNotAvailableException.php';
        throw new Zend_Cloud_OperationNotAvailableException('Deleting metadata not implemented');
    }

    /**
     * Get full path, including bucket, for an object
     *
     * @param  string $path
     * @param  array $options
     * @return void
     */
    protected function _getFullPath($path, $options = array())
    {
        $server = $this->_getServer();
        $protocol = ($server['protocol'])? $server['protocol'] : 'http';
        $path = (!array_key_exists('port', $server) OR $server['port'] == 80)? $protocol.'://'.$server['host'].$path : $protocol.'://'.$server['host'].':'.$server['port'].$path;
        return $path;
    }

    /*
     * Return config of server
     * @return mixed
     * @throws Zend_Cloud_StorageService_Exception
     */
    protected function _getServer($key = NULL)
    {
        if(count($this->_servers) == 0)
            throw new Zend_Cloud_StorageService_Exception('No WebDav servers registered.');
        if(!empty($key) AND array_key_exists($key, $this->_servers))
            return $this->_servers[$key];
        if(!empty($this->_defaultServerKey)) {
            return $this->_servers[$this->_defaultServerKey];
        }
        return array_pop($this->_servers);
    }

    /*
     * Get the concrete client.
     * @return Zend_Http_Client
     */
    public function getClient($getNewInstance = false)
    {
        if($getNewInstance)
            $this->_client = NULL;
        if(empty($this->_client)) {
            $this->_client = new Zend_Http_Client();
            $this->_client->setConfig(array(
                    'maxredirects' => 0,
                    'timeout'      => 30)
            );
        }
        return $this->_client;
    }

    /*
     * Get mime type by extension
     */
    public static function getMimeType($extension) {
        $mimeTypes = self::mimetypeMapping();
        $key = $mimeTypes['extensions'][$extension];
        return $mimeTypes['mimetypes'][$key];
    }

    public static function mimetypeMapping() {
        return array(
            'mimetypes' => array(
                0 => 'application/andrew-inset',
                1 => 'application/atom',
                2 => 'application/atomcat+xml',
                3 => 'application/atomserv+xml',
                4 => 'application/cap',
                5 => 'application/cu-seeme',
                6 => 'application/dsptype',
                7 => 'application/hta',
                8 => 'application/java-archive',
                9 => 'application/java-serialized-object',
                10 => 'application/java-vm',
                11 => 'application/mac-binhex40',
                12 => 'application/mathematica',
                13 => 'application/msaccess',
                14 => 'application/msword',
                15 => 'application/octet-stream',
                16 => 'application/oda',
                17 => 'application/ogg',
                18 => 'application/pdf',
                19 => 'application/pgp-keys',
                20 => 'application/pgp-signature',
                21 => 'application/pics-rules',
                22 => 'application/postscript',
                23 => 'application/rar',
                24 => 'application/rdf+xml',
                25 => 'application/rss+xml',
                26 => 'application/rtf',
                27 => 'application/smil',
                28 => 'application/vnd.cinderella',
                29 => 'application/vnd.google-earth.kml+xml',
                30 => 'application/vnd.google-earth.kmz',
                31 => 'application/vnd.mozilla.xul+xml',
                32 => 'application/vnd.ms-excel',
                33 => 'application/vnd.ms-excel.addin.macroEnabled.12',
                34 => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
                35 => 'application/vnd.ms-excel.sheet.macroEnabled.12',
                36 => 'application/vnd.ms-excel.template.macroEnabled.12',
                37 => 'application/vnd.ms-pki.seccat',
                38 => 'application/vnd.ms-pki.stl',
                39 => 'application/vnd.ms-powerpoint',
                40 => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
                41 => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
                42 => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
                43 => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
                44 => 'application/vnd.ms-word.document.macroEnabled.12',
                45 => 'application/vnd.ms-word.template.macroEnabled.12',
                46 => 'application/vnd.ms-xpsdocument',
                47 => 'application/vnd.oasis.opendocument.chart',
                48 => 'application/vnd.oasis.opendocument.database',
                49 => 'application/vnd.oasis.opendocument.formula',
                50 => 'application/vnd.oasis.opendocument.graphics',
                51 => 'application/vnd.oasis.opendocument.graphics-template',
                52 => 'application/vnd.oasis.opendocument.image',
                53 => 'application/vnd.oasis.opendocument.presentation',
                54 => 'application/vnd.oasis.opendocument.presentation-template',
                55 => 'application/vnd.oasis.opendocument.spreadsheet',
                56 => 'application/vnd.oasis.opendocument.spreadsheet-template',
                57 => 'application/vnd.oasis.opendocument.text',
                58 => 'application/vnd.oasis.opendocument.text-master',
                59 => 'application/vnd.oasis.opendocument.text-template',
                60 => 'application/vnd.oasis.opendocument.text-web',
                61 => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
                62 => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
                63 => 'application/vnd.openxmlformats-officedocument.presentationml.template',
                64 => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                65 => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
                66 => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                67 => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
                68 => 'application/vnd.rim.cod',
                69 => 'application/vnd.smaf',
                70 => 'application/vnd.stardivision.calc',
                71 => 'application/vnd.stardivision.chart',
                72 => 'application/vnd.stardivision.draw',
                73 => 'application/vnd.stardivision.impress',
                74 => 'application/vnd.stardivision.math',
                75 => 'application/vnd.stardivision.writer',
                76 => 'application/vnd.stardivision.writer-global',
                77 => 'application/vnd.sun.xml.calc',
                78 => 'application/vnd.sun.xml.calc.template',
                79 => 'application/vnd.sun.xml.draw',
                80 => 'application/vnd.sun.xml.draw.template',
                81 => 'application/vnd.sun.xml.impress',
                82 => 'application/vnd.sun.xml.impress.template',
                83 => 'application/vnd.sun.xml.math',
                84 => 'application/vnd.sun.xml.writer',
                85 => 'application/vnd.sun.xml.writer.global',
                86 => 'application/vnd.sun.xml.writer.template',
                87 => 'application/vnd.symbian.install',
                88 => 'application/vnd.visio',
                89 => 'application/vnd.wap.wbxml',
                90 => 'application/vnd.wap.wmlc',
                91 => 'application/vnd.wap.wmlscriptc',
                92 => 'application/wordperfect',
                93 => 'application/wordperfect5.1',
                94 => 'application/x-123',
                95 => 'application/x-7z-compressed',
                96 => 'application/x-abiword',
                97 => 'application/x-apple-diskimage',
                98 => 'application/x-bcpio',
                99 => 'application/x-bittorrent',
                100 => 'application/x-cab',
                101 => 'application/x-cbr',
                102 => 'application/x-cbz',
                103 => 'application/x-cdf',
                104 => 'application/x-cdlink',
                105 => 'application/x-chess-pgn',
                106 => 'application/x-cpio',
                107 => 'application/x-debian-package',
                108 => 'application/x-director',
                109 => 'application/x-dms',
                110 => 'application/x-doom',
                111 => 'application/x-dvi',
                112 => 'application/x-flac',
                113 => 'application/x-font',
                114 => 'application/x-freemind',
                115 => 'application/x-futuresplash',
                116 => 'application/x-gnumeric',
                117 => 'application/x-go-sgf',
                118 => 'application/x-graphing-calculator',
                119 => 'application/x-gtar',
                120 => 'application/x-hdf',
                121 => 'application/x-httpd-eruby',
                122 => 'application/x-httpd-php',
                123 => 'application/x-httpd-php-source',
                124 => 'application/x-httpd-php3',
                125 => 'application/x-httpd-php3-preprocessed',
                126 => 'application/x-httpd-php4',
                127 => 'application/x-ica',
                128 => 'application/x-internet-signup',
                129 => 'application/x-iphone',
                130 => 'application/x-iso9660-image',
                131 => 'application/x-java-jnlp-file',
                132 => 'application/x-javascript',
                133 => 'application/x-jmol',
                134 => 'application/x-kchart',
                135 => 'application/x-killustrator',
                136 => 'application/x-koan',
                137 => 'application/x-kpresenter',
                138 => 'application/x-kspread',
                139 => 'application/x-kword',
                140 => 'application/x-latex',
                141 => 'application/x-lha',
                142 => 'application/x-lyx',
                143 => 'application/x-lzh',
                144 => 'application/x-lzx',
                145 => 'application/x-maker',
                146 => 'application/x-mif',
                147 => 'application/x-ms-wmd',
                148 => 'application/x-ms-wmz',
                149 => 'application/x-msdos-program',
                150 => 'application/x-msi',
                151 => 'application/x-netcdf',
                152 => 'application/x-ns-proxy-autoconfig',
                153 => 'application/x-nwc',
                154 => 'application/x-object',
                155 => 'application/x-oz-application',
                156 => 'application/x-pkcs7-certreqresp',
                157 => 'application/x-pkcs7-crl',
                158 => 'application/x-python-code',
                159 => 'application/x-quicktimeplayer',
                160 => 'application/x-redhat-package-manager',
                161 => 'application/x-shar',
                162 => 'application/x-shockwave-flash',
                163 => 'application/x-stuffit',
                164 => 'application/x-sv4cpio',
                165 => 'application/x-sv4crc',
                166 => 'application/x-tar',
                167 => 'application/x-tcl',
                168 => 'application/x-tex-gf',
                169 => 'application/x-tex-pk',
                170 => 'application/x-texinfo',
                171 => 'application/x-trash',
                172 => 'application/x-troff',
                173 => 'application/x-troff-man',
                174 => 'application/x-troff-me',
                175 => 'application/x-troff-ms',
                176 => 'application/x-ustar',
                177 => 'application/x-wais-source',
                178 => 'application/x-wingz',
                179 => 'application/x-x509-ca-cert',
                180 => 'application/x-xcf',
                181 => 'application/x-xfig',
                182 => 'application/x-xpinstall',
                183 => 'application/xhtml+xml',
                184 => 'application/xml',
                185 => 'application/zip',
                186 => 'audio/basic',
                187 => 'audio/midi',
                346 => 'audio/mp4',
                188 => 'audio/mpeg',
                189 => 'audio/ogg',
                190 => 'audio/prs.sid',
                191 => 'audio/x-aiff',
                192 => 'audio/x-gsm',
                193 => 'audio/x-mpegurl',
                194 => 'audio/x-ms-wax',
                195 => 'audio/x-ms-wma',
                196 => 'audio/x-pn-realaudio',
                197 => 'audio/x-realaudio',
                198 => 'audio/x-scpls',
                199 => 'audio/x-sd2',
                200 => 'audio/x-wav',
                201 => 'chemical/x-alchemy',
                202 => 'chemical/x-cache',
                203 => 'chemical/x-cache-csf',
                204 => 'chemical/x-cactvs-binary',
                205 => 'chemical/x-cdx',
                206 => 'chemical/x-cerius',
                207 => 'chemical/x-chem3d',
                208 => 'chemical/x-chemdraw',
                209 => 'chemical/x-cif',
                210 => 'chemical/x-cmdf',
                211 => 'chemical/x-cml',
                212 => 'chemical/x-compass',
                213 => 'chemical/x-crossfire',
                214 => 'chemical/x-csml',
                215 => 'chemical/x-ctx',
                216 => 'chemical/x-cxf',
                217 => 'chemical/x-embl-dl-nucleotide',
                218 => 'chemical/x-galactic-spc',
                219 => 'chemical/x-gamess-input',
                220 => 'chemical/x-gaussian-checkpoint',
                221 => 'chemical/x-gaussian-cube',
                222 => 'chemical/x-gaussian-input',
                223 => 'chemical/x-gaussian-log',
                224 => 'chemical/x-gcg8-sequence',
                225 => 'chemical/x-genbank',
                226 => 'chemical/x-hin',
                227 => 'chemical/x-isostar',
                228 => 'chemical/x-jcamp-dx',
                229 => 'chemical/x-kinemage',
                230 => 'chemical/x-macmolecule',
                231 => 'chemical/x-macromodel-input',
                232 => 'chemical/x-mdl-molfile',
                233 => 'chemical/x-mdl-rdfile',
                234 => 'chemical/x-mdl-rxnfile',
                235 => 'chemical/x-mdl-sdfile',
                236 => 'chemical/x-mdl-tgf',
                237 => 'chemical/x-mmcif',
                238 => 'chemical/x-mol2',
                239 => 'chemical/x-molconn-Z',
                240 => 'chemical/x-mopac-graph',
                241 => 'chemical/x-mopac-input',
                242 => 'chemical/x-mopac-out',
                243 => 'chemical/x-mopac-vib',
                244 => 'chemical/x-ncbi-asn1-ascii',
                245 => 'chemical/x-ncbi-asn1-binary',
                246 => 'chemical/x-ncbi-asn1-spec',
                247 => 'chemical/x-pdb',
                248 => 'chemical/x-rosdal',
                249 => 'chemical/x-swissprot',
                250 => 'chemical/x-vamas-iso14976',
                251 => 'chemical/x-vmd',
                252 => 'chemical/x-xtel',
                253 => 'chemical/x-xyz',
                254 => 'image/gif',
                255 => 'image/ief',
                256 => 'image/jpeg',
                257 => 'image/pcx',
                258 => 'image/png',
                259 => 'image/svg+xml',
                260 => 'image/tiff',
                261 => 'image/vnd.djvu',
                262 => 'image/vnd.microsoft.icon',
                263 => 'image/vnd.wap.wbmp',
                264 => 'image/x-cmu-raster',
                265 => 'image/x-coreldraw',
                266 => 'image/x-coreldrawpattern',
                267 => 'image/x-coreldrawtemplate',
                268 => 'image/x-corelphotopaint',
                269 => 'image/x-jg',
                270 => 'image/x-jng',
                271 => 'image/x-ms-bmp',
                272 => 'image/x-photoshop',
                273 => 'image/x-portable-anymap',
                274 => 'image/x-portable-bitmap',
                275 => 'image/x-portable-graymap',
                276 => 'image/x-portable-pixmap',
                277 => 'image/x-rgb',
                278 => 'image/x-xbitmap',
                279 => 'image/x-xpixmap',
                280 => 'image/x-xwindowdump',
                281 => 'message/rfc822',
                282 => 'model/iges',
                283 => 'model/mesh',
                284 => 'model/vrml',
                285 => 'text/calendar',
                286 => 'text/css',
                287 => 'text/csv',
                288 => 'text/h323',
                289 => 'text/html',
                290 => 'text/iuls',
                291 => 'text/mathml',
                292 => 'text/plain',
                293 => 'text/richtext',
                294 => 'text/scriptlet',
                295 => 'text/tab-separated-values',
                296 => 'text/texmacs',
                297 => 'text/vnd.sun.j2me.app-descriptor',
                298 => 'text/vnd.wap.wml',
                299 => 'text/vnd.wap.wmlscript',
                300 => 'text/x-bibtex',
                301 => 'text/x-boo',
                302 => 'text/x-c++hdr',
                303 => 'text/x-c++src',
                304 => 'text/x-chdr',
                305 => 'text/x-component',
                306 => 'text/x-csh',
                307 => 'text/x-csrc',
                308 => 'text/x-diff',
                309 => 'text/x-dsrc',
                310 => 'text/x-haskell',
                311 => 'text/x-java',
                312 => 'text/x-literate-haskell',
                313 => 'text/x-moc',
                314 => 'text/x-pascal',
                315 => 'text/x-pcs-gcd',
                316 => 'text/x-perl',
                317 => 'text/x-python',
                318 => 'text/x-setext',
                319 => 'text/x-sh',
                320 => 'text/x-tcl',
                321 => 'text/x-tex',
                322 => 'text/x-vcalendar',
                323 => 'text/x-vcard',
                324 => 'video/3gpp',
                325 => 'video/dl',
                326 => 'video/dv',
                327 => 'video/fli',
                328 => 'video/gl',
                329 => 'video/mp4',
                330 => 'video/mpeg',
                331 => 'video/ogg',
                332 => 'video/quicktime',
                333 => 'video/vnd.mpegurl',
                347 => 'video/x-flv',
                334 => 'video/x-la-asf',
                348 => 'video/x-m4v',
                335 => 'video/x-mng',
                336 => 'video/x-ms-asf',
                337 => 'video/x-ms-wm',
                338 => 'video/x-ms-wmv',
                339 => 'video/x-ms-wmx',
                340 => 'video/x-ms-wvx',
                341 => 'video/x-msvideo',
                342 => 'video/x-sgi-movie',
                343 => 'x-conference/x-cooltalk',
                344 => 'x-epoc/x-sisx-app',
                345 => 'x-world/x-vrml',
            ),
            // Extensions added to this list MUST be lower-case.
            'extensions' => array(
                'ez' => 0,
                'atom' => 1,
                'atomcat' => 2,
                'atomsrv' => 3,
                'cap' => 4,
                'pcap' => 4,
                'cu' => 5,
                'tsp' => 6,
                'hta' => 7,
                'jar' => 8,
                'ser' => 9,
                'class' => 10,
                'hqx' => 11,
                'nb' => 12,
                'mdb' => 13,
                'dot' => 14,
                'doc' => 14,
                'bin' => 15,
                'oda' => 16,
                'ogx' => 17,
                'pdf' => 18,
                'key' => 19,
                'pgp' => 20,
                'prf' => 21,
                'eps' => 22,
                'ai' => 22,
                'ps' => 22,
                'rar' => 23,
                'rdf' => 24,
                'rss' => 25,
                'rtf' => 26,
                'smi' => 27,
                'smil' => 27,
                'cdy' => 28,
                'kml' => 29,
                'kmz' => 30,
                'xul' => 31,
                'xlb' => 32,
                'xlt' => 32,
                'xls' => 32,
                'xlam' => 33,
                'xlsb' => 34,
                'xlsm' => 35,
                'xltm' => 36,
                'cat' => 37,
                'stl' => 38,
                'pps' => 39,
                'ppt' => 39,
                'ppam' => 40,
                'pptm' => 41,
                'ppsm' => 42,
                'potm' => 43,
                'docm' => 44,
                'dotm' => 45,
                'xps' => 46,
                'odc' => 47,
                'odb' => 48,
                'odf' => 49,
                'odg' => 50,
                'otg' => 51,
                'odi' => 52,
                'odp' => 53,
                'otp' => 54,
                'ods' => 55,
                'ots' => 56,
                'odt' => 57,
                'odm' => 58,
                'ott' => 59,
                'oth' => 60,
                'pptx' => 61,
                'ppsx' => 62,
                'potx' => 63,
                'xlsx' => 64,
                'xltx' => 65,
                'docx' => 66,
                'dotx' => 67,
                'cod' => 68,
                'mmf' => 69,
                'sdc' => 70,
                'sds' => 71,
                'sda' => 72,
                'sdd' => 73,
                'sdw' => 75,
                'sgl' => 76,
                'sxc' => 77,
                'stc' => 78,
                'sxd' => 79,
                'std' => 80,
                'sxi' => 81,
                'sti' => 82,
                'sxm' => 83,
                'sxw' => 84,
                'sxg' => 85,
                'stw' => 86,
                'sis' => 87,
                'vsd' => 88,
                'wbxml' => 89,
                'wmlc' => 90,
                'wmlsc' => 91,
                'wpd' => 92,
                'wp5' => 93,
                'wk' => 94,
                '7z' => 95,
                'abw' => 96,
                'dmg' => 97,
                'bcpio' => 98,
                'torrent' => 99,
                'cab' => 100,
                'cbr' => 101,
                'cbz' => 102,
                'cdf' => 103,
                'vcd' => 104,
                'pgn' => 105,
                'cpio' => 106,
                'udeb' => 107,
                'deb' => 107,
                'dir' => 108,
                'dxr' => 108,
                'dcr' => 108,
                'dms' => 109,
                'wad' => 110,
                'dvi' => 111,
                'flac' => 112,
                'pfa' => 113,
                'pfb' => 113,
                'pcf' => 113,
                'gsf' => 113,
                'pcf.z' => 113,
                'mm' => 114,
                'spl' => 115,
                'gnumeric' => 116,
                'sgf' => 117,
                'gcf' => 118,
                'taz' => 119,
                'gtar' => 119,
                'tgz' => 119,
                'hdf' => 120,
                'rhtml' => 121,
                'phtml' => 122,
                'pht' => 122,
                'php' => 122,
                'phps' => 123,
                'php3' => 124,
                'php3p' => 125,
                'php4' => 126,
                'ica' => 127,
                'ins' => 128,
                'isp' => 128,
                'iii' => 129,
                'iso' => 130,
                'jnlp' => 131,
                'js' => 132,
                'jmz' => 133,
                'chrt' => 134,
                'kil' => 135,
                'skp' => 136,
                'skd' => 136,
                'skm' => 136,
                'skt' => 136,
                'kpr' => 137,
                'kpt' => 137,
                'ksp' => 138,
                'kwd' => 139,
                'kwt' => 139,
                'latex' => 140,
                'lha' => 141,
                'lyx' => 142,
                'lzh' => 143,
                'lzx' => 144,
                'maker' => 145,
                'frm' => 145,
                'frame' => 145,
                'fm' => 145,
                'book' => 145,
                'fb' => 145,
                'fbdoc' => 145,
                'mif' => 146,
                'wmd' => 147,
                'wmz' => 148,
                'dll' => 149,
                'bat' => 149,
                'exe' => 149,
                'com' => 149,
                'msi' => 150,
                'nc' => 151,
                'pac' => 152,
                'nwc' => 153,
                'o' => 154,
                'oza' => 155,
                'p7r' => 156,
                'crl' => 157,
                'pyo' => 158,
                'pyc' => 158,
                'qtl' => 159,
                'rpm' => 160,
                'shar' => 161,
                'swf' => 162,
                'swfl' => 162,
                'sitx' => 163,
                'sit' => 163,
                'sv4cpio' => 164,
                'sv4crc' => 165,
                'tar' => 166,
                'gf' => 168,
                'pk' => 169,
                'texi' => 170,
                'texinfo' => 170,
                'sik' => 171,
                '~' => 171,
                'bak' => 171,
                '%' => 171,
                'old' => 171,
                't' => 172,
                'roff' => 172,
                'tr' => 172,
                'man' => 173,
                'me' => 174,
                'ms' => 175,
                'ustar' => 176,
                'src' => 177,
                'wz' => 178,
                'crt' => 179,
                'xcf' => 180,
                'fig' => 181,
                'xpi' => 182,
                'xht' => 183,
                'xhtml' => 183,
                'xml' => 184,
                'xsl' => 184,
                'zip' => 185,
                'au' => 186,
                'snd' => 186,
                'mid' => 187,
                'midi' => 187,
                'kar' => 187,
                'mpega' => 188,
                'mpga' => 188,
                'm4a' => 188,
                'mp3' => 188,
                'mp2' => 188,
                'ogg' => 189,
                'oga' => 189,
                'spx' => 189,
                'sid' => 190,
                'aif' => 191,
                'aiff' => 191,
                'aifc' => 191,
                'gsm' => 192,
                'm3u' => 193,
                'wax' => 194,
                'wma' => 195,
                'rm' => 196,
                'ram' => 196,
                'ra' => 197,
                'pls' => 198,
                'sd2' => 199,
                'wav' => 200,
                'alc' => 201,
                'cac' => 202,
                'cache' => 202,
                'csf' => 203,
                'cascii' => 204,
                'cbin' => 204,
                'ctab' => 204,
                'cdx' => 205,
                'cer' => 206,
                'c3d' => 207,
                'chm' => 208,
                'cif' => 209,
                'cmdf' => 210,
                'cml' => 211,
                'cpa' => 212,
                'bsd' => 213,
                'csml' => 214,
                'csm' => 214,
                'ctx' => 215,
                'cxf' => 216,
                'cef' => 216,
                'emb' => 217,
                'embl' => 217,
                'spc' => 218,
                'gam' => 219,
                'inp' => 219,
                'gamin' => 219,
                'fchk' => 220,
                'fch' => 220,
                'cub' => 221,
                'gau' => 222,
                'gjf' => 222,
                'gjc' => 222,
                'gal' => 223,
                'gcg' => 224,
                'gen' => 225,
                'hin' => 226,
                'istr' => 227,
                'ist' => 227,
                'dx' => 228,
                'jdx' => 228,
                'kin' => 229,
                'mcm' => 230,
                'mmd' => 231,
                'mmod' => 231,
                'mol' => 232,
                'rd' => 233,
                'rxn' => 234,
                'sdf' => 235,
                'sd' => 235,
                'tgf' => 236,
                'mcif' => 237,
                'mol2' => 238,
                'b' => 239,
                'gpt' => 240,
                'mopcrt' => 241,
                'zmt' => 241,
                'mpc' => 241,
                'dat' => 241,
                'mop' => 241,
                'moo' => 242,
                'mvb' => 243,
                'prt' => 244,
                'aso' => 245,
                'val' => 245,
                'asn' => 246,
                'ent' => 247,
                'pdb' => 247,
                'ros' => 248,
                'sw' => 249,
                'vms' => 250,
                'vmd' => 251,
                'xtel' => 252,
                'xyz' => 253,
                'gif' => 254,
                'ief' => 255,
                'jpeg' => 256,
                'jpe' => 256,
                'jpg' => 256,
                'pcx' => 257,
                'png' => 258,
                'svgz' => 259,
                'svg' => 259,
                'tif' => 260,
                'tiff' => 260,
                'djvu' => 261,
                'djv' => 261,
                'ico' => 262,
                'wbmp' => 263,
                'ras' => 264,
                'cdr' => 265,
                'pat' => 266,
                'cdt' => 267,
                'cpt' => 268,
                'art' => 269,
                'jng' => 270,
                'bmp' => 271,
                'psd' => 272,
                'pnm' => 273,
                'pbm' => 274,
                'pgm' => 275,
                'ppm' => 276,
                'rgb' => 277,
                'xbm' => 278,
                'xpm' => 279,
                'xwd' => 280,
                'eml' => 281,
                'igs' => 282,
                'iges' => 282,
                'silo' => 283,
                'msh' => 283,
                'mesh' => 283,
                'icz' => 285,
                'ics' => 285,
                'css' => 286,
                'csv' => 287,
                '323' => 288,
                'html' => 289,
                'htm' => 289,
                'shtml' => 289,
                'uls' => 290,
                'mml' => 291,
                'txt' => 292,
                'pot' => 292,
                'text' => 292,
                'asc' => 292,
                'rtx' => 293,
                'wsc' => 294,
                'sct' => 294,
                'tsv' => 295,
                'ts' => 296,
                'tm' => 296,
                'jad' => 297,
                'wml' => 298,
                'wmls' => 299,
                'bib' => 300,
                'boo' => 301,
                'hpp' => 302,
                'hh' => 302,
                'h++' => 302,
                'hxx' => 302,
                'cxx' => 303,
                'cc' => 303,
                'cpp' => 303,
                'c++' => 303,
                'h' => 304,
                'htc' => 305,
                'csh' => 306,
                'c' => 307,
                'patch' => 308,
                'diff' => 308,
                'd' => 309,
                'hs' => 310,
                'java' => 311,
                'lhs' => 312,
                'moc' => 313,
                'pas' => 314,
                'p' => 314,
                'gcd' => 315,
                'pm' => 316,
                'pl' => 316,
                'py' => 317,
                'etx' => 318,
                'sh' => 319,
                'tk' => 320,
                'tcl' => 320,
                'cls' => 321,
                'ltx' => 321,
                'sty' => 321,
                'tex' => 321,
                'vcs' => 322,
                'vcf' => 323,
                '3gp' => 324,
                'dl' => 325,
                'dif' => 326,
                'dv' => 326,
                'fli' => 327,
                'gl' => 328,
                'mp4' => 329,
                'f4v' => 329,
                'f4p' => 329,
                'mpe' => 330,
                'mpeg' => 330,
                'mpg' => 330,
                'ogv' => 331,
                'qt' => 332,
                'mov' => 332,
                'mxu' => 333,
                'lsf' => 334,
                'lsx' => 334,
                'mng' => 335,
                'asx' => 336,
                'asf' => 336,
                'wm' => 337,
                'wmv' => 338,
                'wmx' => 339,
                'wvx' => 340,
                'avi' => 341,
                'movie' => 342,
                'ice' => 343,
                'sisx' => 344,
                'wrl' => 345,
                'vrm' => 345,
                'vrml' => 345,
                'f4a' => 346,
                'f4b' => 346,
                'flv' => 347,
                'm4v' => 348,
            ),
        );
    }
}

А вот пример работы с ним:

Example.php

<?php
// Init storage
/ ** @var ZendExtra_Cloud_StorageService_Adapter_WebDav $storage ** /
$storage = Zend_Cloud_StorageService_Factory::getAdapter(array(
Zend_Cloud_StorageService_Factory::STORAGE_ADAPTER_KEY => 'ZendExtra_Cloud_StorageService_Adapter_WebDav',
ZendExtra_Cloud_StorageService_Adapter_WebDav::SERVERS_KEY   => array(
'static1.site.ru' => array('host' => '1.2.3.4', 'port' => '80')
),
ZendExtra_Cloud_StorageService_Adapter_WebDav::DEFAULT_SERVER_KEY => 'static1.site.ru'
));
// Fetch item
$storage->fetchItem('/upload/news/c3500cc0c4892f3eda2ef3876af567dd.png');
// Store Item
$data = file_get_contents(ROOT_PATH. '/utils/upload_test.txt');
$storage->storeItem('/upload/upload_test.txt', $data);
// Delete item
$storage->deleteItem('/upload/upload_test.txt');
// Copy item (first - without loading item toi client, second - with it)
$storage->copyItem('/upload/upload_test.txt', '/upload/upload_test2.txt');
$storage->copyItem('/upload/upload_test.txt', '/upload/upload_test2.txt', array('native' => false));
// Move item (first - without loading item toi client, second - with it)
$storage->moveItem('/upload/upload_test.txt', '/upload/upload_test3.txt');
$storage->moveItem('/upload/upload_test3.txt', '/upload/upload_test.txt', array('native' => false));
// Rename item (first - without loading item toi client, second - with it)
$storage->renameItem('/upload/upload_test.txt', 'upload_test2.txt');
$storage->renameItem('/upload/upload_test2.txt', 'upload_test.txt', array('native' => false));
// Directory listing (if in nginx allow)
var_dump($storage->listItems('/upload/'));

Фишки

  • Листинг директорий сделан двумя видами. Если вы скомпилили nginx с модулем nginx-dav-ext-module и он поддерживает методы PROPFIND и OPTIONS то юзайте обычный синтаксис. Это подходит и для сторонних служб, типа Яндекс-Диска. Если же модуля нет, то в массиве options передавайте параметр «mode» => ‘get’ и адаптер будет парсить ответ от nginx, полученный по get запросу. Отсюда зависимость от Zend_Dom
  • По-умолчанию такие операции, как копирование, перемещение и переименование осуществляются прямо на сервере (без загрузки файлов клиенту). Это быстро и удобно. Однако может возникнуть ситуация, когда команды MOVE и COPY выключены в nginx. Тогда используйте параметр native => true, В массиве options функций moveItem(), renameItem(), copyItem().
  • Пока не уверен где писать логику выбора сервера в случае наличия кластера из статических серверов. На данный момент она будет в адаптере но я раздумываю о том, чтобы вынести её. В этом случае адаптер будет работать с одним сервером, а не с многими, как сейчас.

Исходники

Исходникик доступны на GitHub:

https://github.com/netandreus/exlibris/tree/master/application/lib/ZendExtra/Cloud/StorageService/Adapter

Яндекс-Диск клиент для Zend Framework

В клиенте реализована поддержка Яндекс-Диска (да в принципе и любого другого сервиса с авторизацией). Вот небольшой примерчик работы с ним.

yandexDiskExample.php

<?php

// Init storage / ** @var ZendExtra_Cloud_StorageService_Adapter_WebDav $storage ** / $storage = Zend_Cloud_StorageService_Factory::getAdapter(array( Zend_Cloud_StorageService_Factory::STORAGE_ADAPTER_KEY => ‘ZendExtra_Cloud_StorageService_Adapter_WebDav’, ZendExtra_Cloud_StorageService_Adapter_WebDav::SERVERS_KEY   => array( ‘static1.site.ru’ => array(‘host’ => ‘webdav.yandex.ru’, ‘protocol’ => ‘https’, ‘port’ => ’80’) ), ZendExtra_Cloud_StorageService_Adapter_WebDav::DEFAULT_SERVER_KEY => ‘static1.site.ru’ ));

// Отображает список файлов в каталоге
$files = $storage->listItems(‘/testfolder/’);

 

Ссылки

WebDav и Nginx

Хочется взять и расстрелять, или ликбез о том, почему не стоит использовать make install

Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социальной сети starlook.ru
Zend_SimpleCloud
Zend_Dom_Query

create_full_put_path on;

PUT DELETE MKCOL COPY MOVE
Share

Спасибо!


Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это:


6 Responses to “Zend Cloud + WebDav + Яндекс.Диск”

  1. seyar:

    круто. всегда тоже хотелось вынести статику на отдельный сервер. а тут уже готовое решение

  2. Alexx:

    А можно пример для я-диска только без ZEND ? Просто на php. Как залить файл на я-диск и получить от него ссылку на скачивание ?

  3. Alexx:

    Андрей, на сколько я понял, статья на хабре была актуальна для сервиса narod.ru. Но это не суть, потому как я таки надыбал файлик webDAV class со всеми необходимыми ф-циями. Почти со всеми. Нет только возможности изменять св-ва залитого файла — сделать его публичным и получить ссылку на его скачивание. Могли бы вы мне в этом вопросе помочь?

    • google.com Андрей Токарчук:

      Ну можно попробовать) А для какого сервиса вы делаете интеграцию? Или это для своего webDAV-сервера?

Комментировать