2 заметки с тегом

кейсы

Немного про блоггинг

В этом посте я хочу рассказать про своё отношение к блоггингу: что мной движет и какие выгоды можно извлечь из своего «личного дневника». Для начала стоит сказать, что у меня был опыт ведения блога в далёком 2009 году. Конечно же, я писал про сам блоггинг, веб-мастеринг, маркетинг. Было очень интересно не только следить за блогами в Google Reader, но и общаться за кулисами блогосферы, просить друзей по аське расшарить твой пост в Твиттере.

Тогда я делал всё по фану и не представлял на какой путь выведет меня это увлечение. Больше всего я любил постить заметки про HTML и CSS (с ними я познакомился в 2005 году на втором курсе лицея), помогать допиливать друзьям блоги на Blogger и WP, а затем рассказывать на весь мир про это. Также баловался «раскруткой» сайтов, SMM в соцсетях и прочей ерундой, которая была популярна в блогосфере. Вместе с ростом количества постов на моём блоге рос и мой скилл в программировании.

Позже я поступил в универ на маркетолога-экономиста и вся эта тема мне просто срывала крышу. Я пробовал пиарить свой блог на Лайфхаре и Хабре. Моими первыми заказчиками на вёрстку шаблонов были блоггеры, а некоторые даже предлагали взяться за SEO-продвижение. Через некоторое время это всё переросло в рутину, былой интерес иссяк, мне казалось, что блоггинг у меня «всё».

Таким образом, я попал в лимб (работаблогучёба), а в конце 2012 года удалил блог и ушёл в изгои, оставив только Твиттер @jebox (кстати говоря, примерно в это время Google Reader закрылся). Всё своё внимание я акцентировал на нескольких проектах на PHP и получении диплома. Изредка делал мелкие заказы, которые приходили в аську. Сейчас жалею, что закрыл блог, т. к. там был нормальный трафик из Гугла и Яндекса.

С августа 2016 года я возобновил ведение блога на другом домене. И вот, через призму отфильтрованных данных, с позиции маркетолога-экономиста, программиста и бывшего блоггера, я делюсь своими новыми целями, которые хочу достичь с помощью блога:

Попасть в тусовку. Проще говоря, заявить о себе в блогосфере, обзавестись контактами с «нужными» людьми. Когда у тебя есть свои читатели и единомышленники, тебе проще идти по намеченному пути. За счёт чего я планирую достичь этот пункт:

    а) комментирования блогов, спам;
    б) активности в Твиттере;
    в) гостевых постов у крутых блоггеров;
    г) ленты блогов на Эгее и бабло.клик;
    д) качественных постов в своём блоге.

Пропиарить свои услуги. В основе этого пункта лежит написание экспертных статей по PHP и смежным технологиям. Я понимаю, что ЦА у меня веб-мастера и околотематика, но здесь фишка в другом — посты должны формировать экспертную единицу и пиарить мои возможности как PHP-программиста [их нужно писать в разговорном жанре, раскрывающие опыт или показывающие какую-нибудь историю]. Например:

     — Наполняем БД тестовыми данными на PHP за 5 минут 353 просмотра
     — Полное руководство по загрузке изображений на PHP 1842 просмотра
     — Как создать временный файл на PHP, когда функция tmpfile() не подходит 5056 просмотров
     — Путеводитель по нововведениям PHP 7.0 и 7.1 1787 просмотров и набирает популярность
     — UploadedUrl — пишем класс для загрузки удалённых файлов на PHP набирает популярность

Показать клиенту кто я такой. Блог — это прибавка к портфолио, как бы socialproof на ваши услуги. В чистом виде ведение блога для поиска клиентов бесполезно, если только ЦА не станет пользоваться этими услугами. Здесь тонкая грань B2B. Я использую домен второго уровня denisyuk.by и пиарю его, где это уместно: письма, Твиттер, профили в соцсетях. Нужно осознать, что клиенты водятся за пределами блога и придут сюда только лишь за тем, что бы проверить кто я такой.

Написать 100 статей. Я поставил такую цель, что бы не расслабляться. Каждую неделю я должен публиковать как минимум один пост. Сейчас уже 23. К концу году думаю сотка набежит. Когда ты чаще пишешь в блог, то получаешь больше внимания. Это я знаю ещё по старому блогу. За много хороших постов блогосфера быстрее примет тебя за своего. Здесь важно следовать своему контент-плану и всегда писать релевантные посты.

Выработать слог. Если вы думаете, что в блог писать легко, то ошибаетесь. Может быть какую-нибудь ерунду постить и легко, но только не экспертные посты, которые требуют проверки фактов. Любые косяки сразу вылазят на ружу, т. к. ЦА… ну сами знаете. Я ставлю перед собой цель пробовать сложные формы постов. Мне это нужно для тренировки слога, наработки стиля текстовых коммуникаций. Это всё про саморазвитие.

Документировать знания. На своём блоге я веду дайджест «Закладки разработчика сайтов». Сюда сливаю самые крутые ссылки по веб-разработке, которые накопились у меня в браузере и Твиттере. В этом плане мне нравится @pronskiy. Он ведёт дайджест на Хабре по PHP и чтобы проверять уникальность материала сделал PHP Digests Search Tool. Возможно в будущем я сделаю подобный инструмент, но сейчас ограничусь блогом. Зацените несколько выпусков:

     — Закладки разработчика сайтов — выпуск #1
     — Закладки разработчика сайтов — выпуск #2
     — Закладки разработчика сайтов — выпуск #3

Блог — это черновик, а не чистовик. Пишите много и от своего имени. Всегда помните о своей ЦА и следуйте стратегии «Win-Win». Ставьте смысл выше слов. Твиттер RSS

Чтиво про пользу от блога:

    О пользе ведения профессионального блога
    Зачем вести блог (несмотря ни на что)
    Зачем вести блог
    Зачем писать в блог
    Неудобная правда о блогах
    Неудобная правда о блогах

    

UploadedUrl — пишем класс для загрузки удалённых файлов на PHP

Задача. Написать класс для загрузки удалённых файлов по URL. Использовать для решения задачи пакет Symfony HttpFoundation. Класс должен иметь настройки и корректно обрабатывать ошибки. Объяснить устройство класса и показать примеры использования.

В Symfony HttpFoundation существует класс UploadedFile, который загружает файлы из $_FILES. Он умеет сохранять файл на диске и безопасно определять MIME-тип. Нам нужно создать класс с такой же функциональностью, но для загрузки удалённых файлов по URL. Свой класс мы назовём UploadedUrl, как бы расширяя Symfony HttpFoundation, и наследуем класс File, чтобы повторить все возможности UploadedFile. Структура нашего проекта будет выглядеть следующим образом:

┌src/
├──Exception/
│  └──UrlException.php
├──UploadedUrl.php
├──tmpfile.php
└──cacert.pem

Файл UploadedUrl.php будет содержать всю логику нашего класса, а остальные будут решать вспомогательные задачи: UrlException.php — класс для обработки исключений, tmpfile.php — класс для работы с временным файлом, cacert.pem — сертификат для безопасного соединения. Для тех, кто хочет сразу посмотреть результат, может скачать код с репозитория denisyukphp/uploaded-url или установить через Composer.

Для загрузки удалённого файла мы задействуем cURL, который скачает весь контент во временный файл, а затем передадим его URI в конструктор класса File. После завершения работы временный файл будет автоматически удалён. Подключить tmpfile.php можно через Composer с моего репозитория denisyukphp/tmpfile. Почему он лучше функции tmpfile() я рассказал на Хабре.

Перед началом написания класса нам необходимо определиться с интерфейсом инициализации. Предлагаю UploadedUrl принимать два аргумента: 1) http:// или https:// ссылку; 2) необязательный массив с настройками. В итоге вот так должен выглядеть запуск класса:

// обычная загрузка удалённого файла
new UploadedUrl('');

// загрузка файла с настройками по умолчанию
new UploadedUrl('', [
    'verify'     => true,
    'cert'       => 'cacert.pem',
    'maxsize'    => null,
    'timeout'    => null,
    'useragent'  => null,
    'buffersize' => 1024,
    'redirects'  => true,
    'maxredirs'  => 10,
    'curl'       => [],
]);

Подробнее о параметрах настроек поговорим чуть ниже, но этих будет вполне достаточно для полноценной работы. В целом схему работы класса можно представить в виде цепочки: получение URL и настроекинициализация и подготовка cURLзапрос и сохранения данных во временный файлобработка ошибок. Далее я буду небольшими блоками строить класс и по действиям в сниппетах кода давать разъяснения.

Посмотреть 258 строк кода UploadedUrl с комментариями
///////////////////////////////////
// 5 // Как пользоваться классом //
///////////////////////////////////

Для быстрого старта достаточно объявить класс new UploadedUrl('') с валидной ссылкой в первом аргументе. После чего с удалённым файлом можно работать на своём сервере. Файл будет находится во временной папке до конца работы PHP и автоматически удалится, если его не переместить в другое место. Ниже привожу примеры использования UploadedUrl с настройками и моими комментариями:

<?php

$file = new Denisyuk\UploadedUrl('http://i.imgur.com/JRorA8V.gif', [

    // Безопасное соединение. Если установить false, то
    // cURL отключит значения CURLOPT_SSL_VERIFYPEER и
    // CURLOPT_SSL_VERIFYHOST.
    'verify' => true,

    // Можно указать директорию с PEM-сертификатами или отдельный файл.
    // По умолчанию используется cacert.pem, свежию версию которого
    // можно скачать на https://curl.haxx.se/docs/caextract.html
    // или самостоятельно настроить автообновление свежего
    // сертификата по ссылке https://curl.haxx.se/ca/cacert.pem
    'cert' => __DIR__,

    // Зададим максимальный размер загружаемого файла
    // в байтах (по умолчанию без ограничений).
    'maxsize' => 1024 * 1024 * 32,

    // Максимальное время выполнения запроса.
    'timeout' => 60,

    // Информация о пользователе (если null, то будет
    // взято из $_SERVER['HTTP_USER_AGENT']).
    'useragent' => null,

    // Это количество байт, через которое cURL будет
    // сверять размер загружаемого файла. В нашем случае,
    // через каждый килобайт будет выполняться ф-я для
    // проверки размера скачанных данных. Для больших
    // размеров установите значение на 2% меньше
    // от разрешённого (для 1Гб установите 1024 * 1024 * 2).
    'buffersize' => 1024,

    // Разрешить следовать перенаправлениям (по умолчанию 10).
    // cURL будет переходит по ссылкам, где HTTP-ответ
    // имеет заголовок с Location.
    'redirects' => true,

    // Количество перенаправлений. Лучше установить
    // больше двух, т. к. возможны перенаправления
    // с HTTP на HTTPS.
    'maxredirs' => 5,

    // другие CURLOPT_* опции
    'curl' => [
        CURLOPT_AUTOREFERER    => true,
        CURLOPT_CONNECTTIMEOUT => 10,
        /* ... */
    ];
]);

Поскольку UploadedUrl будет наследовать класс File, то он также вернёт набор методов класса SplFileInfo. Это расширяет возможности нашего класса. В общем мы имеем мощный инструмент для работы с файлом. Давайте посмотрим какая функциональность нам доступна:

// получить MIME-тип, который можно
// безопасно использовать для валидации
// определённых файлов
$file->getMimeType();

// получить расширение файла
$file->guessExtension();

// переместить файл в другую папку
$file->move(__DIR__ . '/data', 'foobar.jpg');

// получить размер файла
$file->getSize();

// Остальные доступные методы для SplFileInfo можно
// посмотреть на http://php.net/manual/ru/class.splfileinfo.php
/////////////////////////////////////////
// 6 // Выявляем и обрабатываем ошибки //
/////////////////////////////////////////

UploadedUrl сам не бросает исключение в случае ошибок при загрузке файла. Для отслеживания этого процесса можно использовать три метода: isValid() — проверит были ли ошибки в cURL; getErrorMessage() — вернёт сообщение об ошибке, которое можно показать пользователю; getErrorCode() — вернёт код ошибки cURL (можно использовать для написания сообщений об ошибках на своём языке). Как это всё работает показано ниже:

<?php

use Denisyuk\UploadedUrl;
use Denisyuk\Exception\UrlException;

try {
    // (1) ссылка на загружаемый файл
    $url = 'http://windows.php.net/downloads/releases/php-7.1.1-src.zip';

    // (2) загрузим свежую версию PHP, которая весит ~26 Мбайт
    $file = new UploadedUrl($url, [

        // (3) укажем максимальный размер файла 5 Мбайт
        'maxsize' => 1024 * 1024 * 5,
    ]);

    // (4) проверяем на ошибки
    if (!$file->isValid()) {

        // (5) бросаем исключение
        throw new UrlException(
            $file->getErrorMessage(),
            $file->getErrorCode()
        );

        // Здесь мы можем сформировать свои названия
        // ошибок исходя из getErrorCode(), т. к. это
        // код ошибки cURL. Например:
        //
        // $code = $file->getErrorCode();
        // $errors = [
        //     /*  1 */ CURLE_UNSUPPORTED_PROTOCOL => '',
        //     /*  6 */ CURLE_COULDNT_RESOLVE_HOST => '',
        //     /* 22 */ CURLE_HTTP_RETURNED_ERROR  => '',
        //     /* 42 */ CURLE_ABORTED_BY_CALLBACK  => '',
        // ];
        // $message = isset($errors[$code]) ? $errors[$code] : '';
        //
        // Также мы можем использовать свойства класса
        // $file->url и $file->maxsize для написания
        // более красивых названий своим ошибкам.
        //
        // throw new UrlException($message, $code);
    }

    // (6) работаем дальше, если нет ошибок
    echo $file->getMimeType();

// (7) ловим исключение
} catch(UrlException $e) {

    // (8) выводим сообщение об ошибке
    // выведет: 'Файл "php-7.1.1-src.zip" не должен превышать 5 Мбайт.'
    echo $e->getMessage();
}

Я дальше планирую поддерживать и развивать этот класс на denisyukphp/uploaded-url как дополнение к Symfony HttpFoundation. Если у вас есть какие-либо замечания или предложния, то можете отправить их мне на почту a@denisyuk.by или Вконтакте. Буду очень благодарен за любую обратную связь, которая поможет улучшить UploadedUrl. В ближайшее время намереваюсь нормально оформить проект на Гитхабе и добавить несколько косметических улучшений.