{"id":2331,"date":"2012-06-05T10:30:13","date_gmt":"2012-06-05T16:30:13","guid":{"rendered":"http:\/\/bililite.com\/blog\/?p=2331"},"modified":"2012-12-06T08:51:07","modified_gmt":"2012-12-06T14:51:07","slug":"new-bing-api","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2012\/06\/05\/new-bing-api\/","title":{"rendered":"New Bing API"},"content":{"rendered":"<p><a href=\"http:\/\/bililite.com\/blog\/2011\/02\/25\/a-search-box-for-the-website\/\" title=\"A Search Box for the Website\">I use Bing<\/a> for the search box on <a href=\"http:\/\/bililite.com\">bililite.com<\/a>, and it's worked well; simple API, no need to create a custom search engine as with Google. Unfortunately, <a href=\"http:\/\/www.searchenginejournal.com\/bing-search-losing-money\/33906\/\">Microsoft is losing almost half a million dollars an hour<\/a> on Bing, and they want me to make up the difference. Well, not me alone, but they are going to start charging for using their web services. Fortunately, they are (as of now) providing a <a href=\"http:\/\/www.bing.com\/community\/site_blogs\/b\/developer\/archive\/2012\/05\/17\/bing-developer-update-2.aspx\">free tier of up to 5,000 queries a month<\/a>, which is far more than I need.<\/p>\r\n<p>So I have to <a href=\"https:\/\/datamarket.azure.com\/\">sign up for Azure Marketplace<\/a> (Azure is Microsoft's cloud service) and <a href=\"https:\/\/datamarket.azure.com\/dataset\/5BA839F1-12CE-4CCE-BF57-A49D98D29A44\">Subscribe<\/a> to the Bing Web Search API and create an application key. Then I need to convert my <a href=\"http:\/\/bililite.com\/blog\/2011\/02\/25\/a-search-box-for-the-website\/\" title=\"A Search Box for the Website\">old requests<\/a> into the new format. Luckily, Microsoft provides a <a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkID=248077\">migration guide<\/a> (as a Word document!), and that includes sample code in PHP. The biggest difference is the need for <a href=\"http:\/\/en.wikipedia.org\/wiki\/Basic_access_authentication\">HTTP authentication<\/a>. The code from Microsoft works, as long I leave out the proxy line in the context parameters (I guess they only tested their code on local servers) and <a href=\"http:\/\/php.net\/file_get_contents\">file_get_contents<\/a> works on URLs, which is enabled on my service with <a href=\"https:\/\/www.nearlyfreespeech.net\/\">Nearly Free Speech<\/a>. I imagine setting the header similarly with <a href=\"http:\/\/php.net\/curl\">cUrl<\/a> would also work.<\/p>\r\n<p>The other big difference is that they no longer return the total number of results if not all of them were returned. Now they return a parameter <code>__next<\/code> (note two underlines) that contains the URL for getting more results if they are available. Since I'm only showing a limited list, I just need to test for the existence of that parameter to indicate that more results are available.<\/p>\r\n<p>So the updated code is:<\/p>\r\n<!--more-->\r\n<pre>&lt;?\r\n<code class=\"language-php\">\r\n$accountKey = 'your Azure key here';\r\n$q = $_GET['q'];\r\nif (get_magic_quotes_gpc()) $q = stripslashes($q);\r\n\/\/ note that $q is unsafe!\r\n<\/code>\r\n?&gt;\r\n\r\n<code class=\"language-html\">&lt;form method=\"get\" action=\"\"&gt;\r\n  &lt;input name=\"q\" type=\"text\" value=\"&lt;?=htmlentities($q)?&gt;\" \/&gt;\r\n  &lt;input type=\"submit\" value=\"Search\" \/&gt;\r\n&lt;\/form&gt;<\/code>\r\n\r\n&lt;?\r\n<code class=\"language-php\">\r\nfunction sitesearch ($query, $site, $accountKey, $count=NULL){\r\n  \/\/ code from http:\/\/go.microsoft.com\/fwlink\/?LinkID=248077\r\n  $ServiceRootURL =  'https:\/\/api.datamarket.azure.com\/Bing\/Search\/';\r\n  $WebSearchURL = $ServiceRootURL . 'Web?$format=json&Query=';\r\n  $context = stream_context_create(array(\r\n    'http' => array(\r\n      'request_fulluri' => true,       \r\n      'header'  => \"Authorization: Basic \" . base64_encode($accountKey . \":\" . $accountKey)\r\n    ) \r\n  )); \r\n  $request = $WebSearchURL . urlencode(\"'$query site:$site'\"); \/\/ note the extra single quotes\r\n  if ($count) $request .= \"&\\$top=$count\"; \/\/ note the dollar sign before $top--it's not a variable!\r\n  return json_decode(file_get_contents($request, 0, $context));\r\n}\r\n\r\nfunction showresponse ($q, $next, $results){\r\n  $count = count($results);\r\n  if ($count==0){\r\n    $resultwords = 'No results';\r\n  }else if ($next){\r\n    $resultwords = \"More than $count results\";\r\n  }else if ($count == 1){\r\n    $resultwords = '1 result';\r\n  }else{\r\n    $resultwords = \"$count results\";\r\n  }\r\n  echo \"&lt;p&gt;$resultwords found for &lt;strong&gt;\".htmlentities($q).\"&lt;\/strong&gt;&lt;\/p&gt;\\n\";\r\n  if ($count == 0) return;\r\n  echo \"&lt;dl&gt;\\n\";\r\n  foreach ($results as $result) echo \"&lt;dt&gt;&lt;a href='{$result-&gt;Url}'&gt;{$result-&gt;Title}&lt;\/a&gt;&lt;\/dt&gt;\\n&lt;dd&gt;{$result-&gt;Description}&lt;\/dd&gt;\\n\";\r\n  echo \"&lt;\/dl&gt;\\n\";    \r\n}\r\n\r\nif ($q){\r\n  \/\/ get search results\r\n  $result = sitesearch ($q, $_SERVER['HTTP_HOST'], $accountKey, 10);\r\n  showresponse($q, $result-&gt;d-&gt;{__next}, $result-&gt;d-&gt;results);\r\n  $searchURL = 'http:\/\/www.bing.com\/search?q='.urlencode(\"$q site:{$_SERVER['HTTP_HOST']}\");\r\n  echo \"&lt;p&gt;&lt;a href='$searchURL'&gt;See all results&lt;\/a&gt;&lt;p&gt;\\n\";\r\n}\r\n<\/code>\r\n?&gt;<\/pre>\r\n<p>And you can see it in action on the <a href=\"http:\/\/bililite.com\">Bililite home page<\/a>. Note that as of today (June 5, 2012) my domain registrar is in flux and Bing doesn't have many pages for bililite.com. Try the alias of <a href=\"http:\/\/bililite.nfshost.com\">bililite.nfshost.com<\/a> for better search results.<\/p>\r\n<p>Now to wait for the inevitable, when Microsoft cans the whole thing altogether. <a href=\"http:\/\/en.wikipedia.org\/wiki\/TANSTAAFL\">TNSTAAFL<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"I use Bing for the search box on bililite.com, and it's worked well; simple API, no need to create a custom search engine as with Google. Unfortunately, Microsoft is losing almost half a million dollars an hour on Bing, and they want me to make up the difference. Well, not me alone, but they are [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,20],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2331"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=2331"}],"version-history":[{"count":21,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2331\/revisions"}],"predecessor-version":[{"id":2657,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2331\/revisions\/2657"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=2331"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=2331"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=2331"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}