Pull to refresh

Системные скрипты на php для linux, пишем скриншотер

Reading time 6 min
Views 13K
Многие люди считают что php подходит только для разработки сайтиков, и никак не может быть использован, в других областях применения языков программирования, для создания программ… В этой статье я бы хотел осветить, применение php скриптов «не целевым» образом, а именно мы напишем скрипт который будет делать скрин, выгружать его на yandex диск и выводить адрес скриншота в консоль…

Рассмотрим структуру проекта, она очень проста и состоит из 3-х файлов:

1. screen.php — точка входа в приложение.
2. classes/autoload.php — автолоадер проекта.
3. classes/Request.php — класс реализующий запросы к api яндекса.

Далее расмотрим код screen.php:

Код screen.php
#!/usr/bin/php
<?php
require_once('classis/autoload.php');

$request = new Request();

if(isset($argv[1]) && $argv[1] == '--getToken') {
    echo $request->getOauthLink();die;
}

$home = $_SERVER['HOME'];
$config = include($home . '/.config/scrphp/config.php');
$nameScreenshot = date('Y_m_d_G_i_s_') . 'screen.png';

system('scrot -s /tmp/'.$nameScreenshot);

$result = $request
    ->setToken($config['token'])
    ->setFileNameOnDisk($nameScreenshot)
    ->setPathToFile('/tmp/'.$nameScreenshot)
    ->upload()
    ->publicateFile();

$url = $result['public_url'];

echo $url.PHP_EOL;



Как видите это точка входа в приложение, логика проста:
1. Формирование имени скриншота
2. Вызов системной программы scrot
3. Запрос api yandex.disk и выгрузка скриншота

Файл autoload.php тоже очень прост и состоит всего из трёх строк кода, я приведу его лишь для ознакомления, и мы не будем его рассматривать подробно.

spl_autoload_register(function($name){
    require_once __DIR__.'/'.$name.'.php';
});

Работа с yandex api довольно проста я написал небольшой класс Request.php, с набором неких методов, которые помогают мне в работе с ним…

Листинг Request.php
<?php
class Request
{
    private $_token = null;
    private $_href = null;
    private $_method = null;
    private $_filePath = null;
    private $_fileName = null;

    /**
     * get oauth link
     */
    public function getOauthLink()
    {
        /**
         * https://oauth.yandex.ru/authorize?
         * response_type=token
         * & client_id=<идентификатор приложения>
         * [& device_id=<идентификатор устройства>]
         * [& device_name=<имя устройства>]
         * [& display=popup]
         * [& login_hint=<имя пользователя или электронный адрес>]
         * [& force_confirm=yes]
         * [& state=<произвольная строка>]
         */
        $link = 'https://oauth.yandex.ru/authorize'
            .'?response_type=token'
            . '&client_id=8fc231e60575439fafcdb3b9281778a3';
        echo $link;
    }

    /**
     * set file path on disk
     * @param $filePath
     * @return $this
     */
    public function setFileNameOnDisk($name)
    {
        /**
         * https://cloud-api.yandex.net/v1/disk/resources/upload ?
         * path=<путь, по которому следует загрузить файл>
         */
        $link = 'https://cloud-api.yandex.net/v1/disk/resources/upload?path='.urlencode('/'.trim($name,'/'));
        $response = file_get_contents($link,false,$this->_context('GET'));
        $responseAsArray = json_decode($response,true);
        $this->_href = $responseAsArray['href'];
        $this->_method = $responseAsArray['method'];
        $this->_fileName = $name;
        return $this;
    }

    /**
     * get path to file on local disk
     * @param $path
     * @return $this
     */
    public function setPathToFile($path) {
        $this->_filePath = $path;
        return $this;
    }

    /**
     * upload file to disk
     */
    public function upload()
    {
        $ch = curl_init($this->_href);

        curl_setopt($ch,CURLOPT_HTTPHEADER,
            array(
                'Authorization',
                'OAuth '.$this->_token
            )
        );

        curl_setopt($ch,CURLOPT_INFILE,fopen($this->_filePath,"r"));
        curl_setopt($ch,CURLOPT_INFILESIZE,filesize($this->_filePath));
        curl_setopt($ch,CURLOPT_PUT,true);

        curl_exec($ch);
        curl_close($ch);
        return $this;
    }

    /**
     * public file and get public url for screenshot
     * @return mixed
     */
    public function publicateFile()
    {
        /**
         * https://cloud-api.yandex.net/v1/disk/resources/publish ?
         * path=<путь к публикуемому ресурсу>
         */
        $link = 'https://cloud-api.yandex.net/v1/disk/resources/publish?path='.urlencode('/'.trim($this->_fileName,'/'));
        $response = file_get_contents($link,false,$this->_context('PUT'));
        $responseAsArray = json_decode($response,true);
        $publicateFile = file_get_contents($responseAsArray['href'],false,$this->_context($responseAsArray['method']));
        $publicateFileAsArray = json_decode($publicateFile,true);
        return $publicateFileAsArray;
    }

    /**
     * set oauth token
     * @param $key
     * @return $this
     */
    public function setToken($token)
    {
        $this->_token = $token;
        return $this;
    }

    /**
     * get context for request by file_get_contents
     * @param $method
     * @return resource
     */
    private function _context($method)
    {
        /**
         * Authorization: OAuth <key>
         */
        $opts = array(
            'http'=>array(
                'method'=>$method,
                'header'=>"Authorization: OAuth ".$this->_token."\r\n"
            )
        );

        $context = stream_context_create($opts);
        return $context;
    }

}


Рассмотрим ключевые методы данного класса для запроса методов api в основном я использовал file_get_contents, и так как мне приходилось использовать, его при запросе многих методов я написал метод генерации контекста:

    /**
     * get context for request by file_get_contents
     * @param $method
     * @return resource
     */
    private function _context($method)
    {
        /**
         * Authorization: OAuth <key>
         */
        $opts = array(
            'http'=>array(
                'method'=>$method,
                'header'=>"Authorization: OAuth ".$this->_token."\r\n"
            )
        );

        $context = stream_context_create($opts);
        return $context;
    }

Он тоже довольно прост мы создаём контекст с определённом методом запроса и информации об аутентификации…

Далее нам необходимо «создать файл на yandex.disk» это действие мы производим следующим методом:

  /**
     * set file path on disk
     * @param $filePath
     * @return $this
     */
    public function setFileNameOnDisk($name)
    {
        /**
         * https://cloud-api.yandex.net/v1/disk/resources/upload ?
         * path=<путь, по которому следует загрузить файл>
         */
        $link = 'https://cloud-api.yandex.net/v1/disk/resources/upload?path='.urlencode('/'.trim($name,'/'));
        $response = file_get_contents($link,false,$this->_context('GET'));
        $responseAsArray = json_decode($response,true);
        $this->_href = $responseAsArray['href'];
        $this->_method = $responseAsArray['method'];
        $this->_fileName = $name;
        return $this;
    }

Как я говорил ранее мы запрашиваем api с помощью функции file_get_contents. После того как этот метод отработает, и вся информация будет запрошена, запускаеться метод upload:

    /**
     * upload file to disk
     */
    public function upload()
    {
        $ch = curl_init($this->_href);

        curl_setopt($ch,CURLOPT_HTTPHEADER,
            array(
                'Authorization',
                'OAuth '.$this->_token
            )
        );

        curl_setopt($ch,CURLOPT_INFILE,fopen($this->_filePath,"r"));
        curl_setopt($ch,CURLOPT_INFILESIZE,filesize($this->_filePath));
        curl_setopt($ch,CURLOPT_PUT,true);

        curl_exec($ch);
        curl_close($ch);
        return $this;
    }

В данно случае можно было бы использовать для отправки файла одну из функций `file_get_contents` или `file_put_contents` но это не целесообразно, по причине того что пришлось бы, в контексте данных функций, в ручную имитировать заголовки и другие вытекающие из этого проблемы, так что проще просто использовать для этих целей curl.

И так файл загружен, остаёться только опубликовать его и получить прямую ссылку для просмотра, это выполняет функция publicateFile():

    /**
     * public file and get public url for screenshot
     * @return mixed
     */
    public function publicateFile()
    {
        /**
         * https://cloud-api.yandex.net/v1/disk/resources/publish ?
         * path=<путь к публикуемому ресурсу>
         */
        $link = 'https://cloud-api.yandex.net/v1/disk/resources/publish?path='.urlencode('/'.trim($this->_fileName,'/'));
        $response = file_get_contents($link,false,$this->_context('PUT'));
        $responseAsArray = json_decode($response,true);
        $publicateFile = file_get_contents($responseAsArray['href'],false,$this->_context($responseAsArray['method']));
        $publicateFileAsArray = json_decode($publicateFile,true);
        return $publicateFileAsArray;
    }

В этом методе тоже всё довольно просто, мы запрашиваем публикацию файла методом PUT у api, яндекс возвращает ссылку, на которую мы должны выполнить запрос для подтвержедения публикации, и метод запроса в диску. И в конце концов, после второго запроса мы получаем массив который соддержит ссылку на публичный файл.

Установка скрипта


Чтож мы закончили, теперь нам предстоит придумать а как же этот скрипт будет работать из консоли? как его запустить там в «глобальной области»? ответом на эти вопросы будет phar — архив содержащий файлы php и способный выполняться как отдельное приложение, похож на тот же jar.

phar мы будем собирать с помощью утилиты box.phar для этого мы пишем простой конфигурационный файл box.json:

{
    "files": [
	"classis/autoload.php",
        "classis/Request.php",
	"screen.php"
    ],
    "main": "screen.php",
    "output": "srcphp.phar",
    "stub": true
}

Для сборки запускаем:

$ php box.phar build

И наш проект готов теперь осталось только установить права на исполнение файла, и скопировать в директорию /usr/bin/srcphp:

$ chmod +x srcphp.phar
$ cp srcphp.phar /usr/bin/srcphp

Не забываем о конфигурации файла /home/myname/.config/srcphp/config.php:

<?php 
// copy this file to /home/user/.config/srcphp/config.php
return array(
    'token' => 'your token'
);

в token необходимо вписать полученный oAuth токен от яндекса, при переходе сгенерированной по средством запуска скрипта с ключом --getToken:

$ srcphp --getToken

Выводы


Главная мысль статьи — рассмотреть как создать консольное приложение с помощью php, на примере программы скриншотера, в следующих я буду поднимать тему использования php в различных сферах применения, и следующая статью будет посвящена разработки простого драйвера usb устройства для linux. Спасибо за внимание и доброго дня.

p.s. Исходный код приложения
Tags:
Hubs:
+2
Comments 21
Comments Comments 21

Articles