Getting title and meta tags from external website

Viewed 144403

I want to try figure out how to get the

<title>A common title</title>
<meta name="keywords" content="Keywords blabla" />
<meta name="description" content="This is the description" />

Even though if it's arranged in any order, I've heard of the PHP Simple HTML DOM Parser but I don't really want to use it. Is it possible for a solution except using the PHP Simple HTML DOM Parser.

preg_match will not be able to do it if it's invalid HTML?

Can cURL do something like this with preg_match?

Facebook does something like this but it's properly used by using:

<meta property="og:description" content="Description blabla" />

I want something like this so that it is possible when someone posts a link, it should retrieve the title and the meta tags. If there are no meta tags, then it it ignored or the user can set it themselves (but I'll do that later on myself).

21 Answers
<?php
// Assuming the above tags are at www.example.com
$tags = get_meta_tags('http://www.example.com/');

// Notice how the keys are all lowercase now, and
// how . was replaced by _ in the key.
echo $tags['author'];       // name
echo $tags['keywords'];     // php documentation
echo $tags['description'];  // a php manual
echo $tags['geo_position']; // 49.33;-86.59
?>

get_meta_tags will help you with all but the title. To get the title just use a regex.

$url = 'http://some.url.com';
preg_match("/<title>(.+)<\/title>/siU", file_get_contents($url), $matches);
$title = $matches[1];

Hope that helps.

Shouldnt we be using OG?

The chosen answer is good but doesn't work when a site is redirected (very common!), and doesn't return OG tags, which are the new industry standard. Here's a little function which is a bit more usable in 2018. It tries to get OG tags and falls back to meta tags if it cant them:

function getSiteOG( $url, $specificTags=0 ){
    $doc = new DOMDocument();
    @$doc->loadHTML(file_get_contents($url));
    $res['title'] = $doc->getElementsByTagName('title')->item(0)->nodeValue;

    foreach ($doc->getElementsByTagName('meta') as $m){
        $tag = $m->getAttribute('name') ?: $m->getAttribute('property');
        if(in_array($tag,['description','keywords']) || strpos($tag,'og:')===0) $res[str_replace('og:','',$tag)] = $m->getAttribute('content');
    }
    return $specificTags? array_intersect_key( $res, array_flip($specificTags) ) : $res;
}

How to use it:

/////////////
//SAMPLE USAGE:
print_r(getSiteOG("http://www.stackoverflow.com")); //note the incorrect url

/////////////
//OUTPUT:
Array
(
    [title] => Stack Overflow - Where Developers Learn, Share, & Build Careers
    [description] => Stack Overflow is the largest, most trusted online community for developers to learn, shareâ âtheir programming âknowledge, and build their careers.
    [type] => website
    [url] => https://stackoverflow.com/
    [site_name] => Stack Overflow
    [image] => https://cdn.sstatic.net/Sites/stackoverflow/img/apple-touch-icon@2.png?v=73d79a89bded
)

A simple function to understand how to retrieve og:tags, title and description, adapt this for yourself

function read_og_tags_as_json($url){


    $ch = curl_init();

    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

    $HTML_DOCUMENT = curl_exec($ch);
    curl_close($ch);

    $doc = new DOMDocument();
    $doc->loadHTML($HTML_DOCUMENT);

    // fecth <title>
    $res['title'] = $doc->getElementsByTagName('title')->item(0)->nodeValue;

    // fetch og:tags
    foreach( $doc->getElementsByTagName('meta') as $m ){

          // if had property
          if( $m->getAttribute('property') ){

              $prop = $m->getAttribute('property');

              // here search only og:tags
              if( preg_match("/og:/i", $prop) ){

                  // get results on an array -> nice for templating
                  $res['og_tags'][] =
                  array( 'property' => $m->getAttribute('property'),
                          'content' => $m->getAttribute('content') );
              }

          }
          // end if had property

          // fetch <meta name="description" ... >
          if( $m->getAttribute('name') == 'description' ){

            $res['description'] = $m->getAttribute('content');

          }


    }
    // end foreach

    // render JSON
    echo json_encode($res, JSON_PRETTY_PRINT |
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

}

Return for this page (may have more infos) :

{
    "title": "php - Getting title and meta tags from external website - Stack Overflow",
    "og_tags": [
        {
            "property": "og:type",
            "content": "website"
        },
        {
            "property": "og:url",
            "content": "https://stackoverflow.com/questions/3711357/getting-title-and-meta-tags-from-external-website"
        },
        {
            "property": "og:site_name",
            "content": "Stack Overflow"
        },
        {
            "property": "og:image",
            "content": "https://cdn.sstatic.net/Sites/stackoverflow/Img/apple-touch-icon@2.png?v=73d79a89bded"
        },
        {
            "property": "og:title",
            "content": "Getting title and meta tags from external website"
        },
        {
            "property": "og:description",
            "content": "I want to try figure out how to get the\n\n&lt;title&gt;A common title&lt;/title&gt;\n&lt;meta name=\"keywords\" content=\"Keywords blabla\" /&gt;\n&lt;meta name=\"description\" content=\"This is the descript..."
        }
    ]
}

My solution (adapted from parts of cronoklee's & shamittomar's posts) so I can call it from anywhere and get a JSON return. Can be easily parsed into any content.

<?php
header('Content-type: application/json; charset=UTF-8');

if (!empty($_GET['url']))
{
    file_get_contents_curl($_GET['url']);
}
else
{
    echo "No Valid URL Provided.";
}


function file_get_contents_curl($url)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

    $data = curl_exec($ch);
    curl_close($ch);

    echo json_encode(getSiteOG($data), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}

function getSiteOG( $OGdata){
    $doc = new DOMDocument();
    @$doc->loadHTML($OGdata);
    $res['title'] = $doc->getElementsByTagName('title')->item(0)->nodeValue;

    foreach ($doc->getElementsByTagName('meta') as $m){
        $tag = $m->getAttribute('name') ?: $m->getAttribute('property');
        if(in_array($tag,['description','keywords']) || strpos($tag,'og:')===0) $res[str_replace('og:','',$tag)] = utf8_decode($m->getAttribute('content'));

    }

    return $res;
}
?>

I've got this working a different way and thought I'd share it. Less code than others and found it here. I've added a few things to make it load the page meta that you are on instead of a certain page. I wanted this to copy the default page title and description into the og tags automatically.

For some reason though, whatever way (different scripts) I tried, the page loads super slow online but instant on wamp. Not sure why so I'm probably going with a switch case since the site is not huge.

<?php
$url = 'http://sitename.com'.$_SERVER['REQUEST_URI'];
$fp = fopen($url, 'r');

$content = "";

while(!feof($fp)) {
    $buffer = trim(fgets($fp, 4096));
    $content .= $buffer;
}

$start = '<title>';
$end = '<\/title>';

preg_match("/$start(.*)$end/s", $content, $match);
$title = $match[1];

$metatagarray = get_meta_tags($url);
$description = $metatagarray["description"];

echo "<div><strong>Title:</strong> $title</div>";
echo "<div><strong>Description:</strong> $description</div>";
?>

and in the HTML header

<meta property="og:title" content="<?php echo $title; ?>" />
<meta property="og:description" content="<?php echo $description; ?>" />

Improved answer from @shamittomar above to get the meta tags (or the specified one from html source)

Can be improved further... the difference from php's default get_meta_tags is that it works even when there is unicode string

function getMetaTags($html, $name = null)
{
    $doc = new DOMDocument();
    try {
        @$doc->loadHTML($html);
    } catch (Exception $e) {

    }

    $metas = $doc->getElementsByTagName('meta');

    $data = [];
    for ($i = 0; $i < $metas->length; $i++)
    {
        $meta = $metas->item($i);

        if (!empty($meta->getAttribute('name'))) {
            // will ignore repeating meta tags !!
            $data[$meta->getAttribute('name')] = $meta->getAttribute('content');
        }
    }

    if (!empty($name)) {
        return !empty($data[$name]) ? $data[$name] : false;
    }

    return $data;
}
Related