Как стать автором
Поиск
Написать публикацию
Обновить

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

Время на прочтение6 мин
Количество просмотров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. Исходный код приложения
Теги:
Хабы:
Всего голосов 32: ↑17 и ↓15+2
Комментарии21

Публикации

Ближайшие события