News:

Want to get involved in developing SMF, then why not lend a hand on our github!

Main Menu

Meta OG: for facebook..

Started by dodos26, March 30, 2024, 03:28:19 PM

Previous topic - Next topic

dodos26

I noticed that links with a database error appear on Facebook.
I found this to be due to the lack of OG tags.
I decided to create a modification that would fix it.
function Make_OG_Meta() {
    global $context, $scripturl;

    if (isset($context['topic_first_message']) && $context['topic_first_message'] !== null)
    {
        $idPost = $context['topic_first_message'];
        $idTopic = $context['current_topic'];
        $post = Get_Post_Body_OG($idPost);
        if (preg_match('~(\[img\]|\[img\s{0,}.*\])\s{0,}(https\:\/\/.*)\s{0,}\[\/img\]~U', $post['body'], $matches)) {
            $context['html_headers'] .= '
                <meta property="og:url" content="'. $scripturl .'?topic='. $idTopic .'" />
                <meta property="og:type" content="article" />
                <meta property="og:title" content="'. ((strlen($context['subject']) > 35) ? substr($context['subject'], 0, 35) . '..' : $context['subject']) .'" />
                <meta property="og:image" content="'. $matches[2] .'" />
            ';
            return;
        }
    }
    $context['html_headers'] .= '
        <meta property="og:url" content="https //xxx org/" />
        <meta property="og:type" content="video.movie" />
        <meta property="og:title" content="XXX - Forum z Filmami!" />
        <meta property="og:image" content="https // XXX org/Themes/default/images/xxx_placeholder.png" />
    ';
}

function Get_Post_Body_OG($id) {
    global $smcFunc;

    $request = $smcFunc['db_query']('', '
        SELECT body
        FROM {db_prefix}messages
        WHERE id_msg = '. (int)$id .'
        LIMIT 1'
    );

    list($body) = $smcFunc['db_fetch_row']($request);
    $smcFunc['db_free_result']($request);

    if (isset($body) && !empty($body))
        return array('body' => $body);
    else return array('body' => '');
}

Function Make_OG_Meta(); use after:
call_integration_hook('integrate_menu_buttons', array(&$buttons));
in Subs.php


But it doesn't seem to work, the image preview doesn't show up.
And a replacement image appears (xxx_placeholder.png) but in some messages the image does not appear.
Smf 2.0.19 used. Not planed use 2.1

You cannot view this attachment.

Kindred

well, you had better plan to use 2.1 -- or 3.0 -- because 2.0.x is shortly going to be end of life and will not even receive security updates.   Already, there are no plans (AFAIK) to extend the 2.0.x line to support php 8.1 and above


but, why would you add this function and the call directly into the code instead of using the hooks?

Even if you are using it like that, I would assume that you would add it when the page is loading, not when the menu is loaded...
Слaва
Украинi

Please do not PM, IM or Email me with support questions.  You will get better and faster responses in the support boards.  Thank you.

"Loki is not evil, although he is certainly not a force for good. Loki is... complicated."

dodos26

I use https://developers.facebook.com/tools/debug/
and sometimes there is a database error in the downloaded code, it seems to me that it is a problem with INET_ATON. Checking the appache logs, it seems that the facebook scraper uses ipv6..

Apart from these issues
Invalid Image Content Type
Provided og:image URL, https://xxx.org/index.php?action=dlattach;topic=121.0;attach=489;image could not be processed as an image because it has an invalid content type.

Downloading the image from the attachment is incorrect?
Attachments are visible to everyone.

Kindred

Yeah, 2.0.x does not support ipv6

Attachments are not always images...
Слaва
Украинi

Please do not PM, IM or Email me with support questions.  You will get better and faster responses in the support boards.  Thank you.

"Loki is not evil, although he is certainly not a force for good. Loki is... complicated."

dodos26

But that be images... I made sure it was an image. As I guess, it's more about the response type.
"Transfer-Encoding: chunked, Accept-Ranges: bytes, Content-Encoding: none, Content-Transfer-Encoding: binary"
Do you think if I removed it it would work?


Code ("NOT WORK IMAGE RESPONSE") Select
HTTP/1.1 200 OK
Date: Sun, 31 Mar 2024 11:05:34 GMT
Server: Apache/2.4.56 (Debian)
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1
X-Content-Type-Options: nosniff
Expires: Mon, 31 Mar 2025 11:05:34 GMT
Cache-Control: max-age=31536000, private
Pragma:
Content-Encoding: none
Content-Transfer-Encoding: binary
Last-Modified: Sat, 30 Mar 2024 12:27:51 GMT
Accept-Ranges: bytes
Connection: close
ETag: "4897198436.0.jpg1711801671"
Content-Disposition: inline; filename="7198436.0.jpg"
Transfer-Encoding: chunked
Content-Type: image/jpeg

Code ("WORK IMAGE RESPONSE") Select
HTTP/1.1 200 OK
Date: Sun, 31 Mar 2024 11:05:43 GMT
Server: Apache/2.4.56 (Debian)
Last-Modified: Sat, 30 Mar 2024 15:05:41 GMT
ETag: "4eb0-614e216fb5b40"
Accept-Ranges: bytes
Content-Length: 20144
Keep-Alive: timeout=5, max=96
Connection: Keep-Alive
Content-Type: image/png

Facebook use facebookexternalhit/1.1 Can I somehow get information about this or make a workaround for the files for this browser?

dodos26

#5
I did this to solve the problem with inet.

"Even if you are using it like that, I would assume that you would add it when the page is loading, not when the menu is loaded..."
What I would like to do most of all is as you say. Is it possible to do this? I would like to gain access to the body from the first post to extract the first image. I wouldn't have to ask the database about it then.

Code ("Changes in Subs.php") Select
function Make_OG_Meta() {
    global $context, $scripturl;

    if (isset($context['topic_first_message']) && $context['topic_first_message'] !== null)
    {
        $idPost = $context['topic_first_message'];
        $idTopic = $context['current_topic'];
        $post = Get_Post_Body_OG($idPost);
        if (preg_match('~(\[img\]|\[img\s{0,}.*\])\s{0,}(https\:\/\/.*)\s{0,}\[\/img\]~U', $post['body'], $matches)) {
            $image_url = $matches[2];
            $parsed_url = parse_url($image_url);
            if ($parsed_url && isset($parsed_url['host'])) {
                if ($parsed_url['host'] === $_SERVER['HTTP_HOST']) {
                    $image_url = 'https://XXX.org/Sources/Proxy-Image.php?url=' . urlencode($image_url);
                }
            }
            $context['html_headers'] .= '
                <meta property="og:url" content="'. $scripturl .'?topic='. $idTopic .'" />
                <meta property="og:type" content="article" />
                <meta property="og:title" content="'. ((strlen($context['subject']) > 35) ? substr($context['subject'], 0, 35) . '..' : $context['subject']) .'" />
                <meta property="og:description" content="'. $context['subject'] .'" />
                <meta property="og:image" content="'. $image_url .'" />
            ';
            return;
        }
    }
    $context['html_headers'] .= '
        <meta property="og:url" content="https://XXX.org/" />
        <meta property="og:type" content="article" />
        <meta property="og:title" content="XXX - Forum" />
        <meta property="og:description" content="Nowe wysoko jakościowe forum z filmami!" />
        <meta property="og:image" content="https://XXX.org/Themes/default/images/XXX_placeholder.png" />
    ';
}

function Get_Post_Body_OG($id) {
    global $smcFunc;

    $request = $smcFunc['db_query']('', '
        SELECT body
        FROM {db_prefix}messages
        WHERE id_msg = '. (int)$id .'
        LIMIT 1'
    );

    list($body) = $smcFunc['db_fetch_row']($request);
    $smcFunc['db_free_result']($request);

    if (isset($body) && !empty($body))
        return array('body' => $body);
    else return array('body' => '');
}

...

call_integration_hook('integrate_menu_buttons', array(&$buttons));
Make_OG_Meta();

Code ("Make proxy to images") Select
<?php
// Pobranie adresu URL obrazu z parametru GET
$url = isset($_GET['url']) ? $_GET['url'] : '';

// Jeśli adres URL nie został podany lub nie jest prawidłowy, zakończ działanie
if (empty($url) || !filter_var($urlFILTER_VALIDATE_URL)) {
    
header("HTTP/1.1 400 Bad Request");
    exit();
}

// Ograniczenie długości adresu URL
if (strlen($url) > 1000) {
    
header("HTTP/1.1 400 Bad Request");
    echo 
"Adres URL jest zbyt długi.";
    exit();
}

// Sprawdzenie czy domena obrazu jest taka sama jak domena serwera proxy
$image_domain parse_url($urlPHP_URL_HOST);
$proxy_domain $_SERVER['HTTP_HOST']; // Domena serwera proxy
if ($image_domain !== $proxy_domain) {
    
header("HTTP/1.1 403 Forbidden");
    echo 
"Pobrany obraz nie znajduje się na tym samym serwerze co proxy.";
    exit();
}

// Pobranie informacji o pliku
$file_headers get_headers($urltrue);
// Sprawdzenie, czy plik istnieje i jest dostępny
if ($file_headers && strpos($file_headers[0], '200') !== false) {
    
// Sprawdzenie typu zawartości pliku
    
if (isset($file_headers['Content-Type']) && !preg_match('/^image\//'$file_headers['Content-Type'])) {
        
header("HTTP/1.1 403 Forbidden");
        echo 
"Pobrany plik nie jest obrazem.";
        exit();
    }
    
    
// Ustawienie maksymalnego dozwolonego rozmiaru pliku (w bajtach)
    
$max_file_size 10 1024 1024// 10 MB
    // Sprawdzenie rozmiaru pliku
    
if (isset($file_headers['Content-Length']) && $file_headers['Content-Length'] > $max_file_size) {
        
header("HTTP/1.1 403 Forbidden");
        echo 
"Plik jest zbyt duży. Maksymalny dozwolony rozmiar pliku to 10 MB.";
        exit();
    }

    
// Ustawienie nagłówków, aby przekazać obraz bez zmian
    
header("Content-Type: image/jpeg");
    
header("Content-Disposition: inline");
    
// Pobranie danych obrazu
    
$image_data file_get_contents($url);
    
// Wyświetlenie danych obrazu
    
echo $image_data;
} else {
    
// Jeśli plik nie istnieje lub nie jest dostępny, zwróć odpowiednią odpowiedź HTTP
    
header("HTTP/1.1 404 Not Found");
    echo 
"Plik nie istnieje lub nie jest dostępny.";
    exit();
}

Fix Incorrect string value: '''' for function inet_aton File: Sources\Subs.php
Code (found) Select
        $smcFunc['db_insert']($do_delete ? 'ignore' : 'replace',
            '{db_prefix}log_online',
            array('session' => 'string', 'id_member' => 'int', 'id_spider' => 'int', 'log_time' => 'int', 'ip' => 'raw', 'url' => 'string'),
            array($session_id, $user_info['id'], empty($_SESSION['id_robot']) ? 0 : $_SESSION['id_robot'], time(), 'IFNULL(INET_ATON(\'' . $user_info['ip'] . '\'), 0)', $serialized),
            array('session')
        );
Code (replace) Select
        $smcFunc['db_insert']($do_delete ? 'ignore' : 'replace',
            '{db_prefix}log_online',
            array('session' => 'string', 'id_member' => 'int', 'id_spider' => 'int', 'log_time' => 'int', 'ip' => 'raw', 'url' => 'string'),
            array($session_id, $user_info['id'], empty($_SESSION['id_robot']) ? 0 : $_SESSION['id_robot'], time(), ipv6_check($user_info['ip']), $serialized),
            array('session')
        );
AND
Code (found) Select
// Make sure the browser doesn't come back and repost the form data.  Should be used whenever anything is posted.
Code ("add before") Select
function ipv6_check($ip) {
    if (empty($ip)) {
        return '0'; // Jeśli adres IP jest pusty, zwracamy 0
    } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
        return '0'; // Jeśli adres IP jest w formacie IPv6, zwracamy 0
    } else {
        return 'INET_ATON(\'' . $ip . '\')'; // W przeciwnym razie wykonujemy konwersję do formatu numerycznego
    }
}

Effect on facebook:
You cannot view this attachment.

Advertisement: