Счетчик скачиваний файлов посредством YANDEX API

Реализация счетчика файлов на MODX

  • Веб-виджет Сохранить на Яндекс.Диск
  • счетчик файлов на яндекс диске

В предыдущей статье мы с вами рассмотрели методы PROPPATCH | PROPFIND для работы с файлами посредством YANDEX API, теперь же давайте попробуем применить эти знания на практике.

Яндекс Диск — это сервис, который позволяет хранить файлы и обмениваться ими, а также предоставляет доступ к файлам с любого устройства, подключённого к интернету.

Для размещения файлов на своем сайте Яндекс предлагает простой способ размещения - виджет "Сохранить на yandex диск - виджет диска. Позволяет админу сайта быстро закачать файл и предоставить доступ к файлу другим пользователям. Юзеры могут быстро просмотреть web документ, либо же сохранить его на свой Яндекс Диск.

Сегодня мы попробуем реализовать простейший счетчик скачиваний файлов с Яндекс диска посредством API Яндекс Диска

Рассмотрим реализацию методов PROPFIND - получение свойств файла и PROPPATCH - запись свойств файла.

Используемые инструменты:

  • OAuth авторизацию Яндекс
  • Api yandex disk
  • PHP, CURL, MODX Revolution


API Яндекс Диска располагается по адресу webdav.yandex.ru. Соединение должно производиться по протоколу HTTPS (порт 443).
Для работы с сервисом Яндекс нам нужно зарегистрировать наше приложение на сервисе OAuth Yandex на вкладке Регистрация Клиентских приложений 
https://oauth.yandex.ru/client/new

регистрация приложения яндекс

Регистрация клиентского приложения:

  • дать название приложению
  • установить права доступа
  • установить Callback URI

После регистрации нам будут доступны

доступ к яндекс диску для приложений

  • Id приложения: yyyxxxyyyxyyyyyxy_Набор_Символов_ID_Приложения
  • Пароль приложения: yyyxxxyyy_Набор_Символов_Пароль_Приложения

Используя эти пароль приложения и ID приложения сможем получить OAuth-токен для доступа к данным.

Получение OAuth-токен

Получить разрешение на выполнение действий с данными пользователя можно сделав запрос

https://oauth.yandex.ru/authorize?response_type={token|code}&client_id={client_id}

Важно: как вы уже заметили параметр redirect_uri не используется в запросе, его мы указали при регистрации приложения.

Параметры запроса на получение OAuth-токен:

  • response_type- тип ответа, который мы будем запрашивать от OAuth-сервера, имя параметра будет добавлено к redirect_uri
  • token - токен будет передан в составе фрагмента (добавляемого к URI после символа #)
  • code - код подтверждения, будет передан в виде query-параметра (добавляемого к URI после символа ?)
  • client_id - идентификатор, полученный при регистрации Приложения

Логика работы такая - получаем код подтверждения, затем передав код - получаем токен. Мы будем использовать бессрочный токен, поэтому запрос токена выполним один раз и в дальнейшем при запросах будем просто его указывать.

Создадим снипет MODX со следующим кодом для получения токена

<pre>
<?php
$client_id = 'yyyxxxyyyxyyyyyxy_Набор_Символов_ID_Приложения';
$client_secret = 'yyyxxxyyy_Набор_Символов_Пароль_Приложения';
function postKeys($url,$peremen,$headers) {
    $post_arr=array();
    foreach ($peremen as $key=>$value) {
        $post_arr[]=$key."=".$value;
        }
    $data=implode('&',$post_arr);
    
    $handle=curl_init();
    curl_setopt($handle, CURLOPT_URL, $url);
    curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($handle, CURLOPT_POST, true);
    curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
    $response=curl_exec($handle);
    $code=curl_getinfo($handle, CURLINFO_HTTP_CODE);
    return array("code"=>$code,"response"=>$response);
    }
// Если мы еще не получили разрешения от пользователя, отправляем его на страницу для его получения
if (!isset($_GET["code"])) {
   Header("Location: https://oauth.yandex.ru/authorize?response_type=code&client_id=".$client_id);
  die();
   }
// отправляем запрос через CURL
function makeRequest( $url, $postdata = '', $header = 0 ) {
        $curl = curl_init();
        curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1);		
	    curl_setopt( $curl, CURLOPT_HEADER, $header);
	    curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER, 0 );
	    curl_setopt( $curl, CURLOPT_URL, $url );
		curl_setopt( $curl, CURLOPT_POST, 1);
		curl_setopt( $curl, CURLOPT_POSTFIELDS, $postdata);	
	 
	    $result = curl_exec( $curl );
		$http_code = curl_getinfo( $curl, CURLINFO_HTTP_CODE);
		if ( $http_code == 200 || $http_code == 201 || $http_code == 202 || $http_code == 207 )
		{
			
			if ( $header != 0 )
			{ 
                
				$pos = strpos( $result, 'HTTP/1.0 200 Connection established');
				if( $pos == 0 ) {
					$result = substr($result, 36 );
				}
				$header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
				$headers = substr($result, 0, $header_size );
				$body = substr($result, $header_size);
				curl_close( $curl );
				return $body;
			} else 	{
				curl_close( $curl );			
				return $result;	
			}
		} else {echo $http_code;
			curl_close( $curl );
			return false;
		}
	}

function getUserId($token) {
    		$header[] = "GET /me/ HTTP/1.1";
			$header[] = 'Host: api-yaru.yandex.ru';
			$header[] = 'Content-type: application/x-yaru+xml; type=person; charset=utf-8;';
			$header[] = 'Content-length: 0';		
			$res = makeRequest( 'https://api-yaru.yandex.ru/me' . '?oauth_token=' . $token . '&format=json', '', $header);	
			if ( $res !== FALSE ) {
				preg_match( '/urn:ya.ru:person/[0-9]+/', $res, $matches );
				if ( isset($matches) && !empty( $matches[0]) )
				{	
					$res = explode(  '/', $matches[0] );
					if ( isset( $res ) && !empty( $res[1] ) ) return $res[1]; else return -1;		
				} else {
					return -1;
				}	
			} else {
				return -1;
			}	
	}
//
$result=postKeys("https://oauth.yandex.ru/token",
   array(
       'grant_type' => 'authorization_code',
      'code'=> $_GET["code"],
      'client_id'=>$client_id,
        'client_secret'=>$client_secret,
       ),
   array('Content-type: application/x-www-form-urlencoded')
   );
 
if ($result["code"]==200) {
   $result["response"]=json_decode($result["response"],true);
   $token=$result["response"]["access_token"];

echo $token;
}else{
    echo "ЧТО ТО НЕ ТАК ДРУЖОК! Код: ".$result["code"];
    }
</pre>

Сделайте вызов сниппета на странице, которую мы указали ранее как Callback URI.
Если вы разрешили доступ приложения то на экране вы увидите токен. Сохраните его, он нам потребуется для дальнейшей работы.

Создадим другой сниппет для чтения и записи свойств файлов

<?php
$client_id = 'yyyxxxyyyxyyyyyxy_Набор_Символов_ID_Приложения';
$client_secret = 'yyyxxxyyy_Набор_Символов_Пароль_Приложения';

function makeRequest( $option , $uri = '' , $postdata = '' , $header = '' , $url) {
        $curl = curl_init();
        curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, '' . $option . '' . $uri . ' HTTP/1.1');
        curl_setopt( $curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1);
    	curl_setopt( $curl, CURLOPT_HEADER, 0);
	    curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER, 0 );
        curl_setopt( $curl, CURLOPT_URL, $url );
        curl_setopt( $curl, CURLOPT_POST, 0 );
		curl_setopt( $curl, CURLOPT_POSTFIELDS, $postdata);
	
	    $result = curl_exec( $curl );
		$http_code = curl_getinfo( $curl, CURLINFO_HTTP_CODE);
		if ( $http_code == 207 )
		{
			
			if ( $header != 0 )
			{   
            $result = URLDecode($result);
            
            switch($option) {
            case 'PROPPATCH /':{
                $result=-3;
                break;  
                                }
            default:{
                $pos = strpos( $result, 'HTTP/1.1');
                $http = substr($result, $pos+9,3);
                if ( $http == 404 )
    	        {$result=-1;
    	        }
                else
                {
                    $pos = strpos( $result, 'mynamecount')+13;
                    $result = substr( $result, $pos,strpos( $result, '</myprop>')-$pos);
                }
                
                    }
                            };    
                
    			curl_close( $curl );
				return $result;
			} else 	{
				curl_close( $curl );			
				return $result;	
			}
		} else {echo $http_code;
			curl_close( $curl );
			return -2;
		}
	}
//
function property($option, $uri='' , $token , $url , $value) {
        
        switch($option) {
            case 'put':{
            $option='PROPPATCH /';
            $postdata =  '<?xml version="1.0" encoding="utf-8" ?>';
    		$postdata .= '<propertyupdate xmlns="DAV:" xmlns:u="mynamecount">';
			$postdata .= '<set><prop>'; 						 
            $postdata .= '<u:myprop>' . $value . '</u:myprop>';
            $postdata .= '</prop></set>';
			$postdata .= '</propertyupdate>';
            break;}
            default:{
            $option='PROPFIND /';
            $postdata =  '<?xml version="1.0" encoding="utf-8" ?>';
    		$postdata .= '<propfind xmlns="DAV:">';
			$postdata .= '<prop>'; 						 
            $postdata .= '<myprop xmlns="mynamecount"/>';
            $postdata .= '</prop>';
			$postdata .= '</propfind>';}
                        };
        
        if ( $token != -1 )
		{   
                      
			$header[] = 'Host: webdav.yandex.ru';
            $header[] = 'Accept: */*';
            $header[] = 'Depth: 1';
            $header[] = 'Authorization: OAuth ' . $token . '';
            $header[] = 'Content-length: ' . mb_strlen($postdata);
            $header[] = 'Content-Type: application/x-www-form-urlencoded';
  	
            $res = makeRequest($option, $uri, $postdata, $header , $url); 

			return $res;

		} else {
			return false;
		}	
	} 
//
$url = 'https://webdav.yandex.ru/';
$uri = 'Виджеты/'.$name;

if ($action == count) {
   $ress=property('get', $uri , $token = "token" , $url , 0);
   if ($ress == -1) {
       $ress=property('put', $uri , $token = "token" , $url , 0);
       return '<span class="dw-b__t dw-b__t_b"><i class="dw-i"></i>Сохранить | Скачали 0 раз</span>';
   }
   
   return '<span class="dw-b__t dw-b__t_b"><i class="dw-i"></i>Сохранить | Скачали '.$ress.'</span>';
}
if ($action == down) {
       $ress=property('get', $uri , $token = "token" , $url , 0);
       $ress=property('put', $uri , $token = "token" , $url , $ress+1);
       return false;
}

Функция property формирует запрос на чтение | запись свойств файлов
Функция makeRequest выполняет запрос к webdav.yandex.ru - в зависимости от вида запроса (чтение , запись) либо записывает свойство файла (mynamecount), либо возвращает его значение.

Обрабатывать запросы на чтение и запись будет вот этот сниппет

<?php
if ($_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest') {return;}
$action = $_POST['action'];
if (empty($action)) {return;}
$res = '';
///////////////////
switch ($action) {
    case 'count': 
        $param = array(
        'name' => $_POST['name'],
        'action' => 'count'
         );
         $documents = $modx->runSnippet('yaf_token',$param);
         return $documents;
    case 'down': 
        $param = array(
        'name' => $_POST['name'],
        'action' => 'down',
         );
         $documents = $modx->runSnippet('yaf_token',$param);
         return $documents;     
}

Получаем запрос и в зависимости от выбранного действия ($action = 'count' или 'down') вызываем предыдущий сниппет.

На самой странице добавляем jQuery код

$(document).on('click', 'a.dw-b', function(e) {
name = $(this).prev(".dw-h").children( ".dw-l" ).attr('title');
  e.preventDefault();
    jQuery(function($){
        $.post('[[~ID_СТРАНИЦЫ]]', {
            action: 'down',
            name: $.trim(name)  
             });
});          
});

$(document).on('click', 'a.dw-l', function(e) {
name = $(this).attr('title'); 
    jQuery(function($){
        $.post('[[~ID_СТРАНИЦЫ]]', {
            action: 'down',
            name: $.trim(name)  
             });
});          
});
$(document).ready(function(){
$("a[class='dw-l']").each(function(n){
$('.dw-b__t.dw-b__t_b').attr("id", function (n) {
    return n; 
});   
$("#" + n).load('[[~ID_СТРАНИЦЫ]]', {
            action: 'count',
             name: $.trim(this.title)
            });
});
});

Пример счетчика файлов

При загрузке страницы находим все виджеты от yandex диска, берем имя файла и запрашиваем его свойство count, выводим на страницу.

При клике по кнопке или ссылке на файл активируем свойство down, берем имя файла и передаем в сниппет. Получаем свойство count увеличиваем на 1 и записываем обратно.

Таким образом мы реализовали счетчик файлов на MODX посредством YANDEX API и методов PROPPATCH | PROPFIND.

Спасибо за внимание, если будут вопросы или предложения пишите пожалуйста.

Перепечатка данной статьи возможно только со ссылкой на наш сайт.


Комментарии