{"id":214,"date":"2015-04-12T06:08:47","date_gmt":"2015-04-12T06:08:47","guid":{"rendered":"https:\/\/www.hort.net\/techblog\/?p=214"},"modified":"2015-04-12T07:25:55","modified_gmt":"2015-04-12T07:25:55","slug":"detecting-mobile","status":"publish","type":"post","link":"https:\/\/www.hort.net\/techblog\/2015\/04\/12\/detecting-mobile\/","title":{"rendered":"Detecting if a remote connection is mobile in Apache"},"content":{"rendered":"<div class=\"share_buttons_simple_use_buttons\" style=\"padding: 10px 0; display: inline-block\"><div class=\"tweet_button\" style=\"float: left; vertical-align: top\"><a href=\"https:\/\/twitter.com\/share\" class=\"twitter-share-button\" data-url=\"https:\/\/www.hort.net\/techblog\/2015\/04\/12\/detecting-mobile\/\" data-text=\"Detecting if a remote connection is mobile in Apache\" data-count=\"none\">Tweet<\/a><script type=\"text\/javascript\" src=\"https:\/\/platform.twitter.com\/widgets.js\"><\/script><\/div><div class=\"facebook_like_button\" style=\"float: left; vertical-align: top; margin-left: 10px; max-width: 255px\"><iframe src=\"https:\/\/www.facebook.com\/plugins\/like.php?href=https%3A%2F%2Fwww.hort.net%2Ftechblog%2F2015%2F04%2F12%2Fdetecting-mobile%2F&amp;layout=button_count&amp;show_faces=false&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=25\" scrolling=\"no\" frameborder=\"0\" style=\"border:none; overflow:hidden; width:450px; height:25px;\" allowTransparency=\"true\"><\/iframe><\/div><\/div><p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.hort.net\/techblog\/wp-content\/uploads\/2015\/04\/hort.net-mobile-168x300.jpg\" alt=\"hort.net-mobile\" width=\"168\" height=\"300\" class=\"alignright size-medium wp-image-221\" srcset=\"https:\/\/www.hort.net\/techblog\/wp-content\/uploads\/2015\/04\/hort.net-mobile-168x300.jpg 168w, https:\/\/www.hort.net\/techblog\/wp-content\/uploads\/2015\/04\/hort.net-mobile.jpg 312w\" sizes=\"auto, (max-width: 168px) 100vw, 168px\" \/><\/p>\n<p>As many of you have heard, <a href=\"http:\/\/googlewebmastercentral.blogspot.ca\/2015\/02\/finding-more-mobile-friendly-search.html\" target=\"_blank\">Google is requiring that sites pass their &#8216;mobile usability&#8217; test if they want to show up in mobile search rankings<\/a>.  After April 22nd, Google will start rolling out changes to their listings, and those who don&#8217;t pass the test stand to lose a lot of traffic.<\/p>\n<p>I was pretty concerned until I realized that our biggest problem is all of the small menus around our content.  That stuff works fine on a desktop, but fat fingers (compared to a mouse pointer) can&#8217;t discern between tightly spaced links.<\/p>\n<p>So&#8230;  Why not just make all of the menus disappear for mobile users?<\/p>\n<p>It seemed like the easiest way would be to create an environment variable from within Apache.  This would let me either use <a href=\"http:\/\/httpd.apache.org\/docs\/current\/howto\/ssi.html\" title=\"Server Side Include documentation for Apache\" target=\"_blank\">Server Side Includes<\/a> (SSI) or make programmatic changes in scripts.<\/p>\n<p>The trick, of course, was figuring out which visitors were mobile and which ones weren&#8217;t.  Setting an environment variable wouldn&#8217;t be of much use if I was identifying the wrong visitors.<\/p>\n<p>I ended up finding a great Apache regular expression at <a href=\"http:\/\/detectmobilebrowsers.com\/\" target=\"_blank\">detectmobilebrowers.com<\/a>.  Although the regular expression had what I needed, they were using it to rewrite mobile visitors to another URL.  I just wanted to set a variable, not redirect people.  Here&#8217;s what I came up with instead.<\/p>\n<div class=\"horttech-code\">\n<pre class=\"preserve-code-formatting\">\nRewriteEngine On\nRewriteCond %{HTTP_USER_AGENT} (android|bb\\d+|meego).+mobile|avantgo|bada\\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge\\ |maemo|midp|mmp|mobile.+firefox|netfront|opera\\ m(ob|in)i|palm(\\ os)?|phone|p(ixi|re)\\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows\\ ce|xda|xiino [NC,OR]\nRewriteCond %{HTTP_USER_AGENT} ^(1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a\\ wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r\\ |s\\ )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1\\ u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp(\\ i|ip)|hs\\-c|ht(c(\\-|\\ |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac(\\ |\\-|\\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt(\\ |\\\/)|klon|kpt\\ |kwc\\-|kyo(c|k)|le(no|xi)|lg(\\ g|\\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-|\\ |o|v)|zz)|mt(50|p1|v\\ )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v\\ )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-|\\ )|webc|whit|wi(g\\ |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-) [NC]\nRewriteRule ^ - [E=MOBILE_TMP:1]\nRequestHeader add MOBILEUSER %{MOBILE_TMP}e env=MOBILE_TMP\n<\/pre>\n<\/div>\n<p>As you can see, the first three lines came from detectmobilebrowsers.com.  The last two lines set the environment variable in a two-step process.<\/p>\n<p>The mod_rewrite line that starts with RewriteRule sets a variable named MOBILE_TMP to &#8216;1&#8217; if any of the regular expressions match.  Unfortunately, Apache won&#8217;t pass that environment variable on to CGI scripts.  mod_header, however, can pass variables that it sets.  <\/p>\n<p>The last line uses this feature in mod_header to set another variable named HTTP_MOBILEUSER to the value of MOBILE_TMP if MOBILE_TMP is set.  Note that the variable is called HTTP_MOBILEUSER, not MOBILEUSER.  The RequestHeader directive will prepend the string &#8216;HTTP_&#8217; to whatever environment variable you pick.<\/p>\n<p>Most of our pages at hort.net use SSI, so it&#8217;s very easy for me to tell the system to exclude blocks of code for mobile users now.  Here&#8217;s a sample SSI snippet that only includes the files if it&#8217;s a mobile user.  If not, they&#8217;re excluded.<\/p>\n<div class=\"horttech-code\">\n<pre class=\"preserve-code-formatting\">\n&lt;!--#if expr=&quot;${HTTP_MOBILEUSER} != \/1\/&quot; --&gt;\n&nbsp;&nbsp; &lt;!--#include virtual=&quot;\/include\/root-top.html&quot;--&gt;\n&nbsp;&nbsp; &lt;!--#include virtual=&quot;\/include\/vertical-spacer8.html&quot;--&gt;\n&nbsp;&nbsp; &lt;!--#include virtual=&quot;\/include\/root-left.html&quot;--&gt;\n&lt;!--#endif --&gt;\n<\/pre>\n<\/div>\n<p>Another example sets the background color of a page to green for mobile users, but white for desktop users:<\/p>\n<div class=\"horttech-code\">\n<pre class=\"preserve-code-formatting\">\n&lt;!--#if expr=&quot;${HTTP_MOBILEUSER} != \/1\/&quot; --&gt;\n&lt;body bgcolor=&quot;#FFFFFF&quot; vlink=&quot;#668F66&quot; link=&quot;#000000&quot;&gt;\n&lt;!--#else --&gt;\n&lt;body bgcolor=&quot;#004400&quot; vlink=&quot;#668F66&quot; link=&quot;#000000&quot;&gt;\n&lt;!--#endif --&gt;\n<\/pre>\n<\/div>\n<p>Of course, it would be ideal to use CSS for these, but when you have 800,000 legacy pages dating back nearly twenty years this is much simpler!<\/p>\n<p>Sometimes our Perl scripts also had stylistic changes for mobile users too.  In this case, we choose a different image for mobile visitors:<\/p>\n<div class=\"horttech-code\">\n<pre class=\"preserve-code-formatting\">\nif ($ENV{&#039;HTTP_MOBILEUSER&#039;} == 1) {\n&nbsp;&nbsp; $imagedir = &quot;\/mnt\/WWW\/hort.net\/images\/gallery\/mobile&quot;;\n} else {\n&nbsp;&nbsp; $imagedir = &quot;\/mnt\/WWW\/hort.net\/images\/gallery\/desktop&quot;;\n}\n<\/pre>\n<\/div>\n<p>Or:<\/p>\n<div class=\"horttech-code\">\n<pre class=\"preserve-code-formatting\">\n&nbsp;&nbsp;$imagedir = sprintf(qq(\/mnt\/WWW\/hort.net\/images\/gallery\/%s),\n&nbsp;&nbsp;&nbsp;&nbsp; ($ENV{&#039;HTTP_MOBILEUSER&#039;} == 1) ? &quot;mobile&quot; : &quot;desktop&quot;\n&nbsp;&nbsp;);\n<\/pre>\n<\/div>\n<p>Making these changes ended up being easier than I thought, and for that I&#8217;m grateful.  There are still some tweaks to make to hort.net, and we still need to add some mobile navigation options to our pages.  But for now we&#8217;ll continue to show up in the search rankings, our traffic won&#8217;t disappear, and most importantly, people will be able to use our pages on mobile devices.<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"share_buttons_simple_use_buttons\" style=\"padding: 10px 0; display: inline-block\"><div class=\"tweet_button\" style=\"float: left; vertical-align: top\"><a href=\"https:\/\/twitter.com\/share\" class=\"twitter-share-button\" data-url=\"https:\/\/www.hort.net\/techblog\/2015\/04\/12\/detecting-mobile\/\" data-text=\"Detecting if a remote connection is mobile in Apache\" data-count=\"none\">Tweet<\/a><script type=\"text\/javascript\" src=\"https:\/\/platform.twitter.com\/widgets.js\"><\/script><\/div><div class=\"facebook_like_button\" style=\"float: left; vertical-align: top; margin-left: 10px; max-width: 255px\"><iframe src=\"https:\/\/www.facebook.com\/plugins\/like.php?href=https%3A%2F%2Fwww.hort.net%2Ftechblog%2F2015%2F04%2F12%2Fdetecting-mobile%2F&amp;layout=button_count&amp;show_faces=false&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=25\" scrolling=\"no\" frameborder=\"0\" style=\"border:none; overflow:hidden; width:450px; height:25px;\" allowTransparency=\"true\"><\/iframe><\/div><\/div><p>Tweet As many of you have heard, Google is requiring that sites pass their &#8216;mobile usability&#8217; test if they want to show up in mobile search rankings. After April 22nd, Google will start rolling out changes to their listings, and those who don&#8217;t pass the test stand to lose a lot of traffic. I was [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[],"class_list":["post-214","post","type-post","status-publish","format-standard","hentry","category-web-development"],"_links":{"self":[{"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/posts\/214","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/comments?post=214"}],"version-history":[{"count":9,"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/posts\/214\/revisions"}],"predecessor-version":[{"id":224,"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/posts\/214\/revisions\/224"}],"wp:attachment":[{"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/media?parent=214"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/categories?post=214"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hort.net\/techblog\/wp-json\/wp\/v2\/tags?post=214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}