<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0">

<channel>

<title>Блог об аналитике, визуализации данных, data science и BI, заметки с тегом: open graph</title>
<link>http://test.leftjoin.ru/tags/open-graph/</link>
<description></description>
<generator>E2 (v3365; Aegea)</generator>

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


</channel>
</rss>