{"id":1609,"date":"2011-02-25T02:10:43","date_gmt":"2011-02-25T08:10:43","guid":{"rendered":"http:\/\/bililite.nfshost.com\/blog\/?p=1609"},"modified":"2011-02-25T02:26:39","modified_gmt":"2011-02-25T08:26:39","slug":"a-search-box-for-the-website","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2011\/02\/25\/a-search-box-for-the-website\/","title":{"rendered":"A Search Box for the Website"},"content":{"rendered":"<p>I've been <a href=\"\/blog\/2011\/02\/24\/trying-to-search-with-bing-and-failing\/\">playing with search engines<\/a> and for the search API I'm going with Bing; Google <a href=\"http:\/\/news.ycombinator.com\/item?id=1864625\">limits their free API to 100 queries a day and requires creating a custom search engine<\/a>. Bing requires <a href=\"http:\/\/www.bing.com\/developers\/createapp.aspx\">signing up and getting an \"AppID\"<\/a> but from there it's unlimited. <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd251056.aspx\">Documentation<\/a> is, well, Microsoftian: impossible to find and hard to use when you get it, but there's a <a href=\"http:\/\/www.bing.com\/developers\/s\/API%20Basics.pdf\">PDF<\/a> (!) that explains things pretty well. I decided to do everything on the server rather than being fancy with AJAX; the user has to wait either way and usually wants to leave the current page anyway (that's why he's searching!).<!--more--> This is what I came up with:<\/p>\r\n<pre>&lt;?\r\n<code class=\"language-php\">\r\n$appid = 'your app id here'; \/\/ for Bing Search API\r\n$q = $_GET['q'];\r\nif (get_magic_quotes_gpc()) $q = stripslashes($q);\r\n\/\/ note that $q is unsafe!\r\n<\/code>?&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, $appid, $count=NULL){\r\n  $url = \"http:\/\/api.search.live.net\/json.aspx?AppID=$appid&sources=Web&query=\".urlencode(\"$query site:$site\");\r\n  if ($count) $url .= \"&web.count=$count\";\r\n  $ch = curl_init($url);\r\n  curl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);\r\n  $result = curl_exec($ch);\r\n  curl_close($ch);\r\n  return json_decode($result);\r\n}\r\n\r\nfunction showerrors($errors){\r\n  echo \"&lt;p&gt;Search Error&lt;p&gt;\\n\";\r\n  foreach ($errors as $error) echo \"&lt;p&gt;&lt;a href='{$error-&gt;HelpUrl}'&gt;{$error-&gt;Message}&lt;\/a&gt;\\n\";\r\n}\r\n\r\nfunction showresponse ($q, $total, $results){\r\n  $count = count($results);\r\n  if ($count==0){\r\n    $resultwords = 'No results';\r\n  }else if ($total &gt; $count){\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'], $appid, 10);\r\n  if ($result-&gt;SearchResponse-&gt;Errors){\r\n    showerrors($result-&gt;SearchResponse-&gt;Errors);\r\n  }else{\r\n    showresponse($q, $result-&gt;SearchResponse-&gt;Web-&gt;Total, $result-&gt;SearchResponse-&gt;Web-&gt;Results);\r\n  }\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}<\/code><\/pre>\r\n<p>The code works, though I have to say that Google's search gives better results. The advantage of a stable API outweighs that, I think. You can see it in action on the <a href=\"\/\">home page<\/a>.<\/p>\r\n<p>One incredibly stupid thing for Microsoft to miss though: <a href=\"http:\/\/bing.com\">bing.com<\/a> is not a valid URL; you have to use <a href=\"http:\/\/www.bing.com\">www.bing.com<\/a>. Who does that anymore?<\/p>","protected":false},"excerpt":{"rendered":"I've been playing with search engines and for the search API I'm going with Bing; Google limits their free API to 100 queries a day and requires creating a custom search engine. Bing requires signing up and getting an \"AppID\" but from there it's unlimited. Documentation is, well, Microsoftian: impossible to find and hard to [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1609"}],"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=1609"}],"version-history":[{"count":14,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1609\/revisions"}],"predecessor-version":[{"id":1637,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1609\/revisions\/1637"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=1609"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=1609"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=1609"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}