├── OpenGraph.php ├── OpenGraphTest.php └── README.md /OpenGraph.php: -------------------------------------------------------------------------------- 1 | array('activity', 'sport'), 30 | 'business' => array('bar', 'company', 'cafe', 'hotel', 'restaurant'), 31 | 'group' => array('cause', 'sports_league', 'sports_team'), 32 | 'organization' => array('band', 'government', 'non_profit', 'school', 'university'), 33 | 'person' => array('actor', 'athlete', 'author', 'director', 'musician', 'politician', 'public_figure'), 34 | 'place' => array('city', 'country', 'landmark', 'state_province'), 35 | 'product' => array('album', 'book', 'drink', 'food', 'game', 'movie', 'product', 'song', 'tv_show'), 36 | 'website' => array('blog', 'website'), 37 | ); 38 | 39 | /** 40 | * Holds all the Open Graph values we've parsed from a page 41 | * 42 | */ 43 | private $_values = array(); 44 | 45 | /** 46 | * Fetches a URI and parses it for Open Graph data, returns 47 | * false on error. 48 | * 49 | * @param $URI URI to page to parse for Open Graph data 50 | * @return OpenGraph 51 | */ 52 | static public function fetch($URI) { 53 | $curl = curl_init($URI); 54 | 55 | curl_setopt($curl, CURLOPT_FAILONERROR, true); 56 | curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); 57 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 58 | curl_setopt($curl, CURLOPT_TIMEOUT, 15); 59 | curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); 60 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); 61 | curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); 62 | 63 | $response = curl_exec($curl); 64 | 65 | curl_close($curl); 66 | 67 | if (!empty($response)) { 68 | return self::_parse($response); 69 | } else { 70 | return false; 71 | } 72 | } 73 | 74 | /** 75 | * Parses HTML and extracts Open Graph data, this assumes 76 | * the document is at least well formed. 77 | * 78 | * @param $HTML HTML to parse 79 | * @return OpenGraph 80 | */ 81 | static private function _parse($HTML) { 82 | $old_libxml_error = libxml_use_internal_errors(true); 83 | 84 | $doc = new DOMDocument(); 85 | $doc->loadHTML($HTML); 86 | 87 | libxml_use_internal_errors($old_libxml_error); 88 | 89 | $tags = $doc->getElementsByTagName('meta'); 90 | if (!$tags || $tags->length === 0) { 91 | return false; 92 | } 93 | 94 | $page = new self(); 95 | 96 | $nonOgDescription = null; 97 | 98 | foreach ($tags AS $tag) { 99 | if ($tag->hasAttribute('property') && 100 | strpos($tag->getAttribute('property'), 'og:') === 0) { 101 | $key = strtr(substr($tag->getAttribute('property'), 3), '-', '_'); 102 | $page->_values[$key] = $tag->getAttribute('content'); 103 | } 104 | 105 | //Added this if loop to retrieve description values from sites like the New York Times who have malformed it. 106 | if ($tag ->hasAttribute('value') && $tag->hasAttribute('property') && 107 | strpos($tag->getAttribute('property'), 'og:') === 0) { 108 | $key = strtr(substr($tag->getAttribute('property'), 3), '-', '_'); 109 | $page->_values[$key] = $tag->getAttribute('value'); 110 | } 111 | //Based on modifications at https://github.com/bashofmann/opengraph/blob/master/src/OpenGraph/OpenGraph.php 112 | if ($tag->hasAttribute('name') && $tag->getAttribute('name') === 'description') { 113 | $nonOgDescription = $tag->getAttribute('content'); 114 | } 115 | 116 | } 117 | //Based on modifications at https://github.com/bashofmann/opengraph/blob/master/src/OpenGraph/OpenGraph.php 118 | if (!isset($page->_values['title'])) { 119 | $titles = $doc->getElementsByTagName('title'); 120 | if ($titles->length > 0) { 121 | $page->_values['title'] = $titles->item(0)->textContent; 122 | } 123 | } 124 | if (!isset($page->_values['description']) && $nonOgDescription) { 125 | $page->_values['description'] = $nonOgDescription; 126 | } 127 | 128 | //Fallback to use image_src if ogp::image isn't set. 129 | if (!isset($page->values['image'])) { 130 | $domxpath = new DOMXPath($doc); 131 | $elements = $domxpath->query("//link[@rel='image_src']"); 132 | 133 | if ($elements->length > 0) { 134 | $domattr = $elements->item(0)->attributes->getNamedItem('href'); 135 | if ($domattr) { 136 | $page->_values['image'] = $domattr->value; 137 | $page->_values['image_src'] = $domattr->value; 138 | } 139 | } 140 | } 141 | 142 | if (empty($page->_values)) { return false; } 143 | 144 | return $page; 145 | } 146 | 147 | /** 148 | * Helper method to access attributes directly 149 | * Example: 150 | * $graph->title 151 | * 152 | * @param $key Key to fetch from the lookup 153 | */ 154 | public function __get($key) { 155 | if (array_key_exists($key, $this->_values)) { 156 | return $this->_values[$key]; 157 | } 158 | 159 | if ($key === 'schema') { 160 | foreach (self::$TYPES AS $schema => $types) { 161 | if (array_search($this->_values['type'], $types)) { 162 | return $schema; 163 | } 164 | } 165 | } 166 | } 167 | 168 | /** 169 | * Return all the keys found on the page 170 | * 171 | * @return array 172 | */ 173 | public function keys() { 174 | return array_keys($this->_values); 175 | } 176 | 177 | /** 178 | * Helper method to check an attribute exists 179 | * 180 | * @param $key 181 | */ 182 | public function __isset($key) { 183 | return array_key_exists($key, $this->_values); 184 | } 185 | 186 | /** 187 | * Will return true if the page has location data embedded 188 | * 189 | * @return boolean Check if the page has location data 190 | */ 191 | public function hasLocation() { 192 | if (array_key_exists('latitude', $this->_values) && array_key_exists('longitude', $this->_values)) { 193 | return true; 194 | } 195 | 196 | $address_keys = array('street_address', 'locality', 'region', 'postal_code', 'country_name'); 197 | $valid_address = true; 198 | foreach ($address_keys AS $key) { 199 | $valid_address = ($valid_address && array_key_exists($key, $this->_values)); 200 | } 201 | return $valid_address; 202 | } 203 | 204 | /** 205 | * Iterator code 206 | */ 207 | private $_position = 0; 208 | public function rewind() { reset($this->_values); $this->_position = 0; } 209 | public function current() { return current($this->_values); } 210 | public function key() { return key($this->_values); } 211 | public function next() { next($this->_values); ++$this->_position; } 212 | public function valid() { return $this->_position < sizeof($this->_values); } 213 | } 214 | -------------------------------------------------------------------------------- /OpenGraphTest.php: -------------------------------------------------------------------------------- 1 | assertType('OpenGraph', $o); 13 | 14 | $this->assertAttributeEquals( 15 | array( 16 | 'title' => 'Oceans', 17 | 'type' => 'movie', 18 | 'image' => 'http://images.rottentomatoes.com/images/movie/custom/68/10011268.jpg', 19 | 'url' => 'http://www.rottentomatoes.com/m/10011268-oceans/', 20 | 'site_name' => 'Rotten Tomatoes', 21 | ), 22 | '_values', 23 | $o 24 | ); 25 | } 26 | 27 | public function testFetchReturnsFalseForWebsiteWithNoOpenGraphMetadata() 28 | { 29 | $this->assertEquals(FALSE, OpenGraph::fetch('http://www.example.org/')); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open Graph Protocol helper for PHP 2 | 3 | A small library for making accessing of Open Graph Protocol data easier 4 | 5 | ## Note 6 | Keys with a dash (-) in the name are converted to _ for easy access as a property 7 | in PHP 8 | 9 | ## Required Extensions 10 | * DOM for parsing 11 | 12 | ## Usage 13 | require_once('OpenGraph.php'); 14 | 15 | $graph = OpenGraph::fetch('http://www.rottentomatoes.com/m/10011268-oceans/'); 16 | var_dump($graph->keys()); 17 | var_dump($graph->schema); 18 | 19 | foreach ($graph as $key => $value) { 20 | echo "$key => $value"; 21 | } --------------------------------------------------------------------------------