Web-development

test

Создание простого расширения для Chrome

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

Теперь немного более приземленно.
Создаем папку с расширением, например myclickbtn
В ней создаем файл manifest.json, ...
test

PHPStorm в Windows 10 не работает терминал

После обновления Windows на 10 версию PHPStorm не смог запустить терминал. В решении помогает гугл давая ссылку.
Решение сводиться к запуску обычного терминала, клику по управляющей окном панели правой кнопкой мыши и выбора Properties(Свойства).
windows terminal
Внизу ставим галочку на "Use legacy console"(Использовать прежнюю версию консоли)
Использовать прежнюю версию консоли
ОК.
После переходим в PHPStorm и запускаем новый терминал. Все.
test

Youtube парсим картинку превью из кода

youtube image У нас есть текст фрейма поделиться, но нужно получить картинку превью.
Для этого нам нужно выпарсить ID видео и подставить в нужную ссылку:
Youtube генерирует несколько таких ссылок: http://img.youtube.com/vi/<insert-youtube-video-id-here>/0.jpg http://img.youtube.com/vi/<insert-youtube-video-id-here>/1.jpg http://img.youtube.com/vi/<insert-youtube-video-id-here>/2.jpg http://img.youtube.com/vi/<insert-youtube-video-id-here>/3.jpg Что соответствует размерам и аналогично ссылкам в том же порядке: По умолчанию: http://img.youtube.com/vi/<insert-youtube-video-id-here>/default.jpg Для картинок в высоком качестве: http://img.youtube.com/vi/<insert-youtube-video-id-here>/hqdefault.jpg Среднее качество: http://img.youtube.com/vi/<insert-youtube-video-id-here>/mqdefault.jpg Стандартный размер картинки: http://img.youtube.com/vi/<insert-youtube-video-id-here>/sddefault.jpg Максимальный размер картинки: http://img.youtube.com/vi/<insert-youtube-video-id-here>/maxresdefault.jpg Просто выбираем подходящую ссылку.
Я парсил из кода следующей регуляркой:
//кусок кода выбирающий превью для ютуба
preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $this->body, $matches);
            //preg_match("/^(?:http(?:s)?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)\/))([^\?&"'>]+)/", $this->body, $matches);
            if (!empty($matches[1])) $vid_id = $matches[1];
            if (!empty($vid_id)) return "http://img.youtube.com/vi/".$vid_id."/0.jpg";

Такой код вернет нам ссылку с подставленным айди видео, что нам и требовалось.
test

Сниппет JQuery кода, который скролит страницу к нужному элементу, указанному в ссылке

Может кому пригодиться. Код найден где-то на stackoverflow. Если у ссылки путь начинается с hash(#), то при клике код скролит страницу к нужному элементу на странице.
$(function() {
    $("a[href*='#']:not([href='#'])").click(
        function()
        {
        if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname)
        {
            var target = $(this.hash);
            target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
            if (target.length)
            {
                $('html,body').animate({
                    scrollTop: target.offset().top
                }, 1000);
                return false;
            }
        }});
    });
test

Select2 и добавление нового элемента

Нужна была возможность добавлять новый элемент в список если такого элемента у нас еще не было, благо select2 предусматривает подобную возможность. Загвоздка заключалась только в том что мы использовали список с числовыми id как значение и брался из базы данных. Имеем классическую конструкцию из трех таблиц:
материал(id, ..., ..., ...); теги(id,...,...,...); материал_тег(id_material, id_tag);
Так вот, сам select2 мы используем так:
<select id="multiple" class="form-control select2-multiple" multiple name="tags[]"  >
                                {foreach $labels as $label}
                                    <option value="{$label->id}" {if !empty($exists.{$label->id})}selected{/if} >{$label->title}</option>
                                {/foreach}
                            </select>
<script>

    $(document).ready(function () {

        $("#multiple").select2({
            placeholder: "Select or add tags",
            tags: true,
            tokenSeparators: [",", " "],
            createSearchChoice:function(term, data) {
                if ( $(data).filter( function() {
                            return this.text.localeCompare(term)===0;
                        }).length===0)
                {
                    return { id: term, text:term };
                }
            }
        });
</script>
На стороне сервера я использую фреймворк Laravel 5 и в контроллере использую такую часть кода:
//...
//материал
$record = Linkedin_GroupLabel::find($id);
//...
//Сбрасываем связи с тегами
                        $record->tags()->detach();
                        $rtags  = array();
                        foreach ($request->input('tags') as $tag){
//если значение элемента селекта число, значит это id
                            if (is_numeric($tag)){
                                $rtags[] = $tag;
                            }
                            else //в противном случае это новое значение
                            {
                                $new = Linkedin_Label::where('title','=',trim($tag))->first();
                                if (empty($new->id)){
                                    $new = new Linkedin_Label();
                                }
                                $new->title = trim($tag);
                                $new->save();
                                $rtags[] = $new->id;
                            }
                        }
//аттачим айдишники между записями
                        $record->tags()->attach($rtags);

Единственное НО при таком, записи тегов не должны быть только числом, иначе is_numeric подумает что добавлен айдишник, а не новый тег. Очень вероятно что у кого-то есть вариант получше, но данный случай для меня работает.
test

Windows7+Apache2.4+PostgreSQL+Laravel 5= PDO Exception: driver not found

Пришлось все вот это чудо поднимать, так как нужно делать серверную и клиентскую часть под одну задачу. Искренне не понимаю тех веб-девелоперов которые работают веб-разработкой под Windows )) ну да ладно, это их личное дело.

Итак, проблема следующая:
Windows 7+Apache2.4+PostgreSQL+Laravel = PDO Exception: driver not found
При этом команда:
php -m
Показывает что как pgsql так и pdo_pgsql есть, но Laravel 5 уверенно доказывает обратное. При этом в php.ini:
extension=php_pdo_pgsql.dll
extension=php_pgsql.dll
раскомментированны.

Но вот команда:
php -a
Вызывающая интерактивную консоль php, так же сообщает:
Unable to load dynamic library `D:\WebServer\php\ext\php_pgsql.dll` - тут вместо сообщения какая-то каша, но явно что-то не в порядке.

Оказалось, не хватает dll для данных расширений.

Нужны библиотеки:


libpq.dll, libiconv-2.dll и libintl-8.dll Взять их можно в установленном PostgreSQL, в папке:
C:\Program Files\PostgreSQL\9.4\bin\
вместо 9.4 может быть ваша версия.
Копируем их в:
apache\bin\

Вместо libiconv-2.dll у меня лежала iconv.dll, на всякий случай скинул как есть, так и копию переименованную в libiconv-2.dll
Перезапускаем apache и видим что Laravel 5 на эту проблему больше не ругается.
test

DOMDocument проблемы с кодировкой

В один прекрасный момент заметил что до этого работающий парсер начал вместо нормального текста показывать крокодилов. Недолгие поиски привели к решению:
<?php
$url = file_get_contents('your-xml-file.xml');
//именно эти строчки и выравнивают всю кривость кодировки
$url = mb_convert_encoding($url, 'utf-8', mb_detect_encoding($string));
$url = mb_convert_encoding($url, 'html-entities', 'utf-8');
$dom = new DOMDocument();
$dom->loadHTML($url);
$page_content = $dom->saveHTML();
Все.
test

Laravel 5: собственная кастомная страница не найдена (404)

Задача:

Выводить собственную страницу 404

Решение:

Открываем файл app/Exceptions/Handler.php и немного меняем код функции render:
//...
public function render($request, Exception $e)
{
//customize 404 page
if ($this->isHttpException($e)) {

$statusCode = $e->getStatusCode();

switch ($statusCode) {
case '404':
//путь к файлу с HTML разметкой
return response()->view('front/notfound');
}
}
return parent::render($request, $e);
}
//...
Вот собственно и все. Нашел как-то на страницах интернета, ссылку на источник не помню.
test

Laravel 5: генерируем Sitemap.xml

Задача создавать Sitemap.xml по крону.

Как и говорит нам документация по Laravel 5. В нем уже есть готовый планировщик, достаточно добавить его один раз в крон, а все нужные задачи подключать уже в него. Создаем задачи для планировщика
#php artisan make:console XMLSitemap
Console command created successfully.
Новый файл будет создан по пути...
test

Laravel 5: Middleware удаляющий конечный слеш в пути url

Задача

Если в конце ссылки присутствует символ "/" делать редирект 301 на страницу без него самого.
Задача типичная, значит решение найти не сложно
Итак, создаем Middleware:
#php artisan make:middleware RedirectTrailingSlash
Middleware created successfully.
Заполняем наш файл (app/Middleware/RedirectTrailingSlash.php) соответствующим кодом:
<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Str;

class RedirectTrailingSlash {

/**
* Handle an incoming request.
*
* @param  \Illuminate\Http\Request  $request
* @param  \Closure  $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (preg_match('/.+\/$/', $request->getRequestUri()))
{
//в исходном коде использовалась другая функция редиректа, выбивало ошибку
return redirect(rtrim($request->getRequestUri(), '/'), 301);
}
return $next($request);
}
}

Регистрируем наш Middleware в Http/Kernel.php:
'front.trailingslash'=>'App\Http\Middleware\RedirectTrailingSlash',

Используем. Я использовал его в конструкторе базового контроллера, чтобы все наследующие контроллеры его выполняли:
//...
class BaseController extends Controller {

//...
public function __construct()
{
$this->middleware('front.trailingslash');
//...
}
//...
}

Все. Теперь при переходе на ссылку вида /our/url/ нас перешлет на /our/url
test

Laravel 5 + CKEditor = простой Fileuploader

CKEditor Нужно мне к очередному проекту прикрутить CKEditor + простой загрузчик файлов. Использовать внешний загрузчик не вижу смысла, а тот интерфейс который предоставляет нам CKEditor для загрузки файлов нам вполне годиться. Сам проект использует базовый фреймворк Laravel 5.
Создаем контроллер для загрузки файлов, выполнив команду из консоли:
test

Чиним поломаную табличку в MySQL\MariaDB: Table 'sources_template_fields_value' doesn't exist in engine.

Получил ошибку в MySQL/MariaDB:
Table 'sources_template_fields_value' doesn't exist in engine

До этого переносил базу файлами, просто скопировав /var/lib/mysql

Чтобы починить нужно для нужной таблицы выполнить следующие команды:
alter table sources_template_fields_value discard tablespace;
alter table sources_template_fields_value import tablespace;

После этого табличка снова в строю.
test

MySQL: 985-NULL=NULL

Там где обычная логика не действует, действует какая-то сказочная. Вот так и в этом случае, неожиданно, в сложном запросе с подзапросом нужно выбрать сумму товаров всех, и отнять сумму товаров с определенной категории.
select (sum(total_price)-(select sum(z_sum) from user_orders where user_id=4  and zennobox=1 and status=2)) as sum from user_orders where user_id=4;


И тут так получилось что все время на тестовый запрос я получал NULL. Начал проверять и оказалось что число-NULL = NULL. Печально, когда даже не догадываешься о таком. Но решение тут простое, добавляем функцию ifnull(value,default):
select (sum(total_price)-ifnull((select sum(z_sum) from user_orders where user_id=4  and zennobox=1 and status=2),0)) as sum from user_orders where user_id=4;


Получаем то что нужно. Очередная мелочь, которая привносит небольшие приключения в нашу жизнь.
test

Установка PhantomJS и CasperJS на Debian GNU\Linux

Собственно для тех кто не знает что такое PhantomJS, вещает хабр:
PhantomJS это все плюшки WebKit из консоли с управлением на JS и поддержкой различных стандартов и технологий: DOM, CSS, JSON, Canvas и SVG.

Прикручивают его для разных целей, для тестирования, парсинга и для любой другой автоматизации связанной с загрузкой страниц, особенно с поддержкой JavaScript.

CasperJS - это надстройка над PhantomJS позволяющая более удобно его использовать. Добавляется сохранение скриншота части страниц, более удобная работа со страницей и другие плюшки.

Страницы

Subscribe to RSS - Web-development