1 минута чтения
23 февраля 2021 г.
Генерация Open Graph Image в Эгее
Протокол Open Graph нужен, чтобы управлять представлением контента сайта в социальных сетях. По сути — это набор тегов, позволяющий задать то, как будет отображаться информация о сайте на других площадках. В том числе можно указать картинку, которая будет отображаться в постах. Сегодня мы посмотрим, как для блога на Эгее доработать Open Graph разметку и заострим внимание на Open Graph Image — мы сделаем так, чтобы для каждого поста генерировалась своя картинка с наименованием материала.
Подготовка
Перед настройкой тегов протокола Open Graph сделаем скрипт, который генерирует изображения. В результате картинка представляет собой фон и два текста: время чтения и название материала, поэтому мы заранее подготовили такое фоновое изображение для ВКонтакте:
Подробнее об оформлении сниппетов для ВКонтакте можно почитать в документации.
У социальных сетей разные требования по размеру изображений: ВКонтакте, например, рекомендует 510×228 пикселей. В корне сайта создадим папку og-image-files. Перейдём в неё, положим туда подготовленное фоновое изображение и создадим ещё одну папку внутри под названием og-fonts для шрифтов на изображении.
Написание скрипта для генерации изображения
Скрипт будем писать на php. Так как он генерирует картинку с пользовательским текстом, мы реализуем поддержку параметров, переданных в ссылке. Создаём в директории og-image-files файл og-image.php и открываем его. Весь код, написанный на php нужно заключить в тег <?php … >. Первым делом опишем функцию, которая откроет фоновое изображение. Пробуем открыть изображение и вернуть его. Если не удалось — создаём пустое белое и выводим сообщение об ошибке на нём.
<?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;
}
?>
Следом опишем другую функцию: она будет помещать текст на картинку, автоматически расставляя переносы строки. Она принимает картинку, размер текста, угол наклона, отступ слева и сверху, цвет текста, шрифт, сам текст и максимальную ширину. Внутри строка делится на массив слов, считаются все необходимые значения ширины текста, а затем в цикле for элементы массива помещаются на изображение.
<?php
function imagettftextjustified(&$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(" ", $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 > $largest_line_height) $largest_line_height = $line_height;
if (($linewidth[$lineno] + $line_width + $minspacing) > $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 <= $lineno;$ln++)
{
$slack = $max_width - $linewidth[$ln];
if (($linewordcount[$ln] > 1) && ($ln != $lineno)) $spacing = ($slack / ($linewordcount[$ln] — 1));
else $spacing = $minspacing;
$x = 0;
for ($w = 0;$w < $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;
}
?>
Теперь основная часть: так как при переходе на страницу со скриптом должна отображаться исключительно картинка формата png, указываем Content-Type как image/png. Затем читаем изображение и получаем первый параметр social_network — он пригодится, если вы хотите в зависимости от социальной сети вставлять разные фоновые изображения. Загружаем картинку и получаем второй параметр — text. Все пробелы будут переформатированы в «%20», поэтому методом str_replace возвращаем всё обратно. Время чтения — параметр time_for_read, а time_ending — слово, которое нужно подставить после числа минут. Далее загружаем нужные шрифты.
Так как параметры принимаются через ссылку, в теории, туда можно передать любой SQL-запрос — это называется SQL-инъекцией. Такую брешь можно устранить, если все числовые переменные ещё раз перевести в числовые типы данных, а в строках экранировать кавычки: для этого есть функция mysql_escape_string(). А ещё в строку могут передать HTML-теги — для удаления тегов можно воспользоваться функцией strip_tags().
<?php
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';
?>
Задаём нужные цвета для текста и подставляем текст на изображение. Функцией imagepng выводим изображение, а затем его удаляем для освобождения памяти.
<?php
$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, "Время чтения – ".$time_for_read." ".$time_ending, 1000, 10, 1);
imagepng($img);
imagedestroy($img);
?>
После размещения скрипта на сайте можно сразу протестировать его работу: так как наш лежит на сайте leftjoin.ru в директории og-image-files, можно пройти по ссылке leftjoin.ru/og-image-files/og-image.php и увидеть следующее изображение:
Оно пустое, так как мы не передали параметров. Они передаются непосредственно в ссылку. Например, передача текста и наименования социальной сети выглядит так:
https://leftjoin.ru/og-image-files/og-image.php?text=Hello%20world&social_network=vk
Настраиваем теги протокола Open Graph
Откроем файл с тегом <header> сайта. В случае Эгеи это system/theme/templates/head.tmpl.php. Кое-какие теги предварительно размечены: например, в цикле все изображения отмечаются как og-image, что позволяет при публикации материала в социальных сетях выбирать из карусели картинку для сниппета.
А мы структурируем все теги и собираем вместе под комментарием «OPEN GRAPH PROTOCOL». В Эгее все нужные данные по каждой статье уже лежат в переменных, например, заголовок материала лежит в $content[’title’], а краткое описание страницы можно получить функцией array_keys(content). Главное для нас — добавить такую строку:
<meta property="og:image" content='https://leftjoin.ru/og-image-files/og-image.php?text=<?=urlencode($content['title'])?>&time_for_read=<?=urlencode($time_for_read)?>&time_ending=<?=urlencode($time_ending)?>‘ />
Она задаёт тег og-image и принимает в content изображение. Туда мы подставляем ссылку на скрипт со всеми параметрами-переменными, обработав их функцией urlencode — она и заменяет все пробелы на «%20». Если ей не воспользоваться, то текст на изображениях в социальных сетях вроде ВКонтакте, Facebook, Twitter и даже в мессенджере Telegram будет отображаться нормально, а вот в Slack вместо пробелов останутся символы «%20», даже с учётом их обработки в скрипте ранее. Должен получиться похожий блок:
<!-- OPEN GRAPH PROTOCOL-->
<meta name="og:description" content="<?array_keys(content)?>» />
<meta property="og:image" content='https://leftjoin.ru/og-image-files/og-image.php?text=<?=urlencode($content['title'])?>&time_for_read=<?=urlencode($time_for_read)?>&time_ending=<?=urlencode($time_ending)?>‘ />
<?php foreach ($content['og-images'] as $image): ?>
<meta property="og:image" content="<?=$image?>«/>
<?php endforeach ?>
<meta property="og:image:type" content="image/png" />
<meta name="vk:image" content='https://leftjoin.ru/og-image-files/og-image.php?text=<?=urlencode($content['title'])?>&time_for_read=<?=urlencode($time_for_read)?>&time_ending=<?=urlencode($time_ending)?>&social_network=vk’ >
<meta name="twitter:card" content="summary_large_image">
<meta property="twitter:image" content='https://leftjoin.ru/og-image-files/og-image.php?text=<?=urlencode($content['title'])?>&time_for_read=<?=urlencode($time_for_read)?>&time_ending=<?=urlencode($time_ending)?>‘ />
<meta name="viewport" content="<?= $content['meta-viewport'] ?>«>
<title><?= $content['title'] ?></title>
<meta name="og:title" content="<?= $content['title'] ?>» />
<meta property='og:type' content="article" />
<meta name="og:url" content="<?= $content['current-href'] ?>» />
В результате мы написали скрипт, который генерирует изображение с текстом-параметром прямо на сайте, а затем вызвали этот скрипт в тегах протокола Open Graph. В качестве доработки можно добавить изображения разных размеров и генерировать картинку в зависимости от социальной сети. Теги тоже могут отличаться — изображение для ВКонтакте вставляется в тег <vk:image>, а для Twitter — <twitter:image>. В примере выше указано правильное использование этих тегов.
Комментарии
Добавить комментарий
[ Рекомендации ]
Читайте также
1 минута чтения
8 октября 2020
[ Связаться ]
Давайте раскроем потенциал вашего бизнеса вместе
Заполните форму на бесплатную консультацию
Нужна помощь, запускал скрипт на Эгее v3820, картинка даже не генерируется на этапе проверки скрипта. Блог расположен по адресу site.ru/blog, стоит PHP 7.4.6. Проблема в PHP, да?
К сожалению, не в курсе