{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "Блог об аналитике, визуализации данных, data science и BI, заметки с тегом: эгея",
    "home_page_url": "http:\/\/test.leftjoin.ru\/tags\/egeya\/",
    "feed_url": "http:\/\/test.leftjoin.ru\/tags\/egeya\/json\/",
    "icon": "http:\/\/test.leftjoin.ru\/user\/userpic@2x.jpg",
    "author": {
        "name": "Николай Валиотти",
        "url": "http:\/\/test.leftjoin.ru\/",
        "avatar": "http:\/\/test.leftjoin.ru\/user\/userpic@2x.jpg"
    },
    "items": [
        {
            "id": "98",
            "url": "http:\/\/test.leftjoin.ru\/all\/open-graph-image\/",
            "title": "Генерация Open Graph Image в Эгее",
            "content_html": "<p>Протокол Open Graph нужен, чтобы управлять представлением контента сайта в социальных сетях. По сути — это набор тегов, позволяющий задать то, как будет отображаться информация о сайте на других площадках. В том числе можно указать картинку, которая будет отображаться в постах. Сегодня мы посмотрим, как для блога на Эгее доработать Open Graph разметку и заострим внимание на Open Graph Image — мы сделаем так, чтобы для каждого поста генерировалась своя картинка с наименованием материала.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/1-25.png\" width=\"538\" height=\"310\" alt=\"\" \/>\n<\/div>\n<h2>Подготовка<\/h2>\n<p>Перед настройкой тегов протокола Open Graph сделаем скрипт, который генерирует изображения. В результате картинка представляет собой фон и два текста: время чтения и название материала, поэтому мы заранее подготовили такое фоновое изображение для ВКонтакте:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/2-23.png\" width=\"1400\" height=\"627\" alt=\"\" \/>\n<\/div>\n<p class=\"note\">Подробнее об оформлении сниппетов для ВКонтакте можно почитать в <a href=\"https:\/\/vk.com\/dev\/publications?f=3.%20Оформление%20внешних%20ссылок\">документации<\/a><\/p>\n<p>У социальных сетей разные требования по размеру изображений: ВКонтакте, например, рекомендует 510×228 пикселей. В корне сайта создадим папку og-image-files. Перейдём в неё, положим туда подготовленное фоновое изображение и создадим ещё одну папку внутри под названием og-fonts для шрифтов на изображении.<\/p>\n<h2>Написание скрипта для генерации изображения<\/h2>\n<p>Скрипт будем писать на php. Так как он генерирует картинку с пользовательским текстом, мы реализуем поддержку параметров, переданных в ссылке. Создаём в директории og-image-files файл og-image.php и открываем его. Весь код, написанный на php нужно заключить в тег &lt;?php … >. Первым делом опишем функцию, которая откроет фоновое изображение. Пробуем открыть изображение и вернуть его. Если не удалось — создаём пустое белое и выводим сообщение об ошибке на нём.<\/p>\n<p><details><br \/>\n<summary><span style=\"color:#7ea9b8\">Функция загрузки изображения<\/span><\/summary><\/p>\n<pre class=\"e2-text-code\"><code>&lt;?php\r\nfunction LoadPNG($imgname)\r\n{\r\n   $im = @imagecreatefrompng($imgname);\r\n\r\n   if(!$im)\r\n   {\r\n       $im  = imagecreatetruecolor(150, 30);\r\n       $bgc = imagecolorallocate($im, 255, 255, 255);\r\n       $tc  = imagecolorallocate($im, 0, 0, 0);\r\n\r\n       imagefilledrectangle($im, 0, 0, 150, 30, $bgc);\r\n\r\n       imagestring($im, 1, 5, 5, 'Ошибка загрузки ' . $imgname, $tc);\r\n   }\r\n\r\n   return $im;\r\n}<\/code><\/pre><p><\/details><\/p>\n<p>Следом опишем другую функцию: она будет помещать текст на картинку, автоматически расставляя переносы строки. Она принимает картинку, размер текста, угол наклона, отступ слева и сверху, цвет текста, шрифт, сам текст и максимальную ширину. Внутри строка делится на массив слов, считаются все необходимые значения ширины текста, а затем в цикле for элементы массива помещаются на изображение.<\/p>\n<p><details><br \/>\n<summary><span style=\"color:#7ea9b8\">Функция загрузки изображения<\/span><\/summary><\/p>\n<pre class=\"e2-text-code\"><code>function imagettftextjustified(&amp;$image, $size, $angle, $left, $top, $color, $font, $text, $max_width, $minspacing = 3, $linespacing = 1)\r\n{\r\n   $wordwidth = array();\r\n   $linewidth = array();\r\n   $linewordcount = array();\r\n   $largest_line_height = 0;\r\n   $lineno = 0;\r\n   $words = explode(&quot; &quot;, $text);\r\n   $wln = 0;\r\n   $linewidth[$lineno] = 0;\r\n   $linewordcount[$lineno] = 0;\r\n   foreach ($words as $word)\r\n   {\r\n       $dimensions = imagettfbbox($size, $angle, $font, $word);\r\n       $line_width = $dimensions[2] - $dimensions[0];\r\n       $line_height = $dimensions[1] - $dimensions[7];\r\n       if ($line_height &gt; $largest_line_height) $largest_line_height = $line_height;\r\n       if (($linewidth[$lineno] + $line_width + $minspacing) &gt; $max_width)\r\n       {\r\n           $lineno++;\r\n           $linewidth[$lineno] = 0;\r\n           $linewordcount[$lineno] = 0;\r\n           $wln = 0;\r\n       }\r\n       $linewidth[$lineno] += $line_width + $minspacing;\r\n       $wordwidth[$lineno][$wln] = $line_width;\r\n       $wordtext[$lineno][$wln] = $word;\r\n       $linewordcount[$lineno]++;\r\n       $wln++;\r\n   }\r\n   for ($ln = 0;$ln &lt;= $lineno;$ln++)\r\n   {\r\n       $slack = $max_width - $linewidth[$ln];\r\n       if (($linewordcount[$ln] &gt; 1) &amp;&amp; ($ln != $lineno)) $spacing = ($slack \/ ($linewordcount[$ln] - 1));\r\n       else $spacing = $minspacing;\r\n       $x = 0;\r\n       for ($w = 0;$w &lt; $linewordcount[$ln];$w++)\r\n       {\r\n           imagettftext($image, $size, $angle, $left + intval($x) , $top + $largest_line_height + ($largest_line_height * $ln * $linespacing) , $color, $font, $wordtext[$ln][$w]);\r\n           $x += $wordwidth[$ln][$w] + 20; \/\/+ $spacing + $minspacing;\r\n       }\r\n   }\r\n   return true;\r\n}<\/code><\/pre><p><\/details><\/p>\n<p>Теперь основная часть: так как при переходе на страницу со скриптом должна отображаться исключительно картинка формата png, указываем Content-Type как image\/png. Затем читаем изображение и получаем первый параметр social_network — он пригодится, если вы хотите в зависимости от социальной сети вставлять разные фоновые изображения. Загружаем картинку и получаем второй параметр — text. Все пробелы будут переформатированы в «%20», поэтому методом str_replace возвращаем всё обратно. Время чтения — параметр time_for_read, а time_ending — слово, которое нужно подставить после числа минут. Далее загружаем нужные шрифты.<\/p>\n<p>Так как параметры принимаются через ссылку, в теории, туда можно передать любой SQL-запрос — это называется SQL-инъекцией. Такую брешь можно устранить, если все числовые переменные ещё раз перевести в числовые типы данных, а в строках экранировать кавычки: для этого есть функция mysql_escape_string(). А ещё в строку могут передать HTML-теги — для удаления тегов можно воспользоваться функцией strip_tags().<\/p>\n<p class=\"note\">Функция mysql_escape_string() ещё работает в php5, но была удалена в php7. Подробнее об альтернативах можно почитать в <a href=\"https:\/\/www.php.net\/manual\/ru\/function.mysql-real-escape-string.php\">документации<\/a><\/p>\n<pre class=\"e2-text-code\"><code>header('Content-Type: image\/png');\r\n\r\n$social_network = $_GET['social_network'];\r\n$social_network = mysql_escape_string(strip_tags($social_network));\r\n\r\n$img = LoadPNG('og-image-vk.png');\r\n$text = $_GET['text'];\r\n$text = mysql_escape_string(strip_tags($text));\r\nstr_replace('%20', ' ', $text);\r\n$time_for_read = $_GET['time_for_read'];\r\n$time_for_read = intval($time_for_read);\r\n$time_ending = $_GET['time_ending'];\r\n$time_ending = mysql_escape_string(strip_tags($time_ending));\r\n$tahoma_bold_font_path = '\/og-fonts\/Tahoma-Bold.ttf';\r\n$tahoma_regular_font_path = '\/og-fonts\/Tahoma-Regular.ttf';\r\n$prosto_font_path = '\/og-fonts\/ProstoOne-Regular.ttf';<\/code><\/pre><p>Задаём нужные цвета для текста и подставляем текст на изображение. Функцией imagepng выводим изображение, а затем его удаляем для освобождения памяти.<\/p>\n<pre class=\"e2-text-code\"><code>$white_color = imagecolorallocate($img, 255, 255, 255);\r\n$mentol_color = imagecolorallocate($img, 135, 244, 191);\r\nimagettftextjustified($img, 45, 0, 55, 200, $white_color, $prosto_font_path, $text, 1000, 10, 1.2);\r\nimagettftextjustified($img, 15, 0, 110, 63, $mentol_color, $prosto_font_path, &quot;Время чтения – &quot;.$time_for_read.&quot; &quot;.$time_ending, 1000, 10, 1);\r\nimagepng($img);\r\nimagedestroy($img);\r\n?&gt;<\/code><\/pre><p>После размещения скрипта на сайте можно сразу протестировать его работу: так как наш лежит на сайте leftjoin.ru в директории og-image-files, можно пройти по ссылке leftjoin.ru\/og-image-files\/og-image.php и увидеть следующее изображение:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/3@2x.png\" width=\"720\" height=\"450\" alt=\"\" \/>\n<\/div>\n<p>Оно пустое, так как мы не передали параметров. Они передаются непосредственно в ссылку. Например, передача текста и наименования социальной сети выглядит так:<\/p>\n<pre class=\"e2-text-code\"><code>http:\/\/test.leftjoin.ru\/og-image-files\/og-image.php?text=Hello%20world&amp;social_network=vk<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/4@2x.png\" width=\"720\" height=\"450\" alt=\"\" \/>\n<\/div>\n<h2>Настраиваем теги протокола Open Graph<\/h2>\n<p>Откроем файл с тегом &lt;header> сайта. В случае Эгеи это system\/theme\/templates\/head.tmpl.php. Кое-какие теги предварительно размечены: например, в цикле все изображения отмечаются как og-image, что позволяет при публикации материала в социальных сетях выбирать из карусели картинку для сниппета.<\/p>\n<p>А мы структурируем все теги и собираем вместе под комментарием «OPEN GRAPH PROTOCOL». В Эгее все нужные данные по каждой статье уже лежат в переменных, например, заголовок материала лежит в $content[’title’], а краткое описание страницы можно получить функцией array_keys(content). Главное для нас — добавить такую строку:<\/p>\n<pre class=\"e2-text-code\"><code>&lt;meta property=&quot;og:image&quot; content='http:\/\/test.leftjoin.ru\/og-image-files\/og-image.php?text=&lt;?=urlencode($content['title'])?&gt;&amp;time_for_read=&lt;?=urlencode($time_for_read)?&gt;&amp;time_ending=&lt;?=urlencode($time_ending)?&gt;' \/&gt;<\/code><\/pre><p>Она задаёт тег og-image и принимает в content изображение. Туда мы подставляем ссылку на скрипт со всеми параметрами-переменными, обработав их функцией urlencode — она и заменяет все пробелы на «%20». Если ей не воспользоваться, то текст на изображениях в социальных сетях вроде ВКонтакте, Facebook, Twitter и даже в мессенджере Telegram будет отображаться нормально, а вот в Slack вместо пробелов останутся символы «%20», даже с учётом их обработки в скрипте ранее. Должен получиться похожий блок:<\/p>\n<pre class=\"e2-text-code\"><code>&lt;!-- OPEN GRAPH PROTOCOL--&gt;\r\n&lt;meta name=&quot;og:description&quot; content=&quot;&lt;?array_keys(content)?&gt;&quot; \/&gt;\r\n&lt;meta property=&quot;og:image&quot; content='http:\/\/test.leftjoin.ru\/og-image-files\/og-image.php?text=&lt;?=urlencode($content['title'])?&gt;&amp;time_for_read=&lt;?=urlencode($time_for_read)?&gt;&amp;time_ending=&lt;?=urlencode($time_ending)?&gt;' \/&gt;\r\n&lt;?php foreach ($content['og-images'] as $image): ?&gt;\r\n&lt;meta property=&quot;og:image&quot; content=&quot;&lt;?=$image?&gt;&quot;\/&gt;\r\n&lt;?php endforeach ?&gt;\r\n&lt;meta property=&quot;og:image:type&quot; content=&quot;image\/png&quot; \/&gt;\r\n&lt;meta name=&quot;vk:image&quot; content='http:\/\/test.leftjoin.ru\/og-image-files\/og-image.php?text=&lt;?=urlencode($content['title'])?&gt;&amp;time_for_read=&lt;?=urlencode($time_for_read)?&gt;&amp;time_ending=&lt;?=urlencode($time_ending)?&gt;&amp;social_network=vk' &gt;\r\n&lt;meta name=&quot;twitter:card&quot; content=&quot;summary_large_image&quot;&gt;\r\n&lt;meta property=&quot;twitter:image&quot; content='http:\/\/test.leftjoin.ru\/og-image-files\/og-image.php?text=&lt;?=urlencode($content['title'])?&gt;&amp;time_for_read=&lt;?=urlencode($time_for_read)?&gt;&amp;time_ending=&lt;?=urlencode($time_ending)?&gt;' \/&gt;\r\n&lt;meta name=&quot;viewport&quot; content=&quot;&lt;?= $content['meta-viewport'] ?&gt;&quot;&gt;\r\n&lt;title&gt;&lt;?= $content['title'] ?&gt;&lt;\/title&gt;\r\n&lt;meta name=&quot;og:title&quot; content=&quot;&lt;?= $content['title'] ?&gt;&quot; \/&gt;\r\n&lt;meta property='og:type' content=&quot;article&quot; \/&gt;\r\n&lt;meta name=&quot;og:url&quot; content=&quot;&lt;?= $content['current-href'] ?&gt;&quot; \/&gt;<\/code><\/pre><p>В результате мы написали скрипт, который генерирует изображение с текстом-параметром прямо на сайте, а затем вызвали этот скрипт в тегах протокола Open Graph. В качестве доработки можно добавить изображения разных размеров и генерировать картинку в зависимости от социальной сети. Теги тоже могут отличаться — изображение для ВКонтакте вставляется в тег &lt;vk:image>, а для Twitter — &lt;twitter:image>. В примере выше указано правильное использование этих тегов.<\/p>\n",
            "date_published": "2021-02-24T14:53:54+03:00",
            "date_modified": "2021-02-24T17:24:38+03:00",
            "image": "http:\/\/test.leftjoin.ru\/pictures\/1-25.png",
            "_date_published_rfc2822": "Wed, 24 Feb 2021 14:53:54 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "98",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "http:\/\/test.leftjoin.ru\/pictures\/1-25.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/2-23.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/3@2x.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/4@2x.png"
                ]
            }
        }
    ],
    "_e2_version": 3365,
    "_e2_ua_string": "E2 (v3365; Aegea)"
}