dotMobimobiForgemobiReadyDeviceAtlasgoMobi
background image

Creating Mobile Sites in Drupal Using Multisites

Section Feature Image
Posted by admin - 18 Jan 2007
Twitter share icon Facebook share icon Google Plus share icon

This article provides a quick way to make your Drupal site accessible to mobile devices through two options:
  1. Have a one site serve multiple devices using one code base
  2. Use multisites to render content accordingly using one code base
By doing this your site should be simultaneously available to both mobile and desktop browsers.

Table of Contents

1. Overview
Outline of what this article is all about
2. Function of this script
The scripts functionality, what is does and what it does not
3. Skill Level
Developer knowledge required to implement the script
4. Requirements
Server set up
5. Files Included
All the files included in this module
6. Usage
How to use
7. Code
Summary of the relevant code arrange into snippets
8. Configuration
Summary of the relevant code arrange into snippets
9. Summary
Overview of what has been achieved
10. References and additional information
Inspiration and future developments

1. Overview

This article provides a quick way to make your site accessible to mobile devices through two options

  1. Have a one site serve multiple devices using one code base
  2. Use multisites to render content accordingly using one code base

The basis of the scripts include could be used stand-alone. The template engine used in this article is phptemplate.

2. Function of this script

The scripts included in this article checks to see if the device is a handheld browser using $_SERVER["HTTP_USER_AGENT"], and works out the best type of data to send to it using $_SERVER["HTTP_ACCEPT"] values.

3. Skill Level

Intermediate PHP and Drupal knowledge level is required. Developer must have prior knowledge of setting up multisites.

4. Requirements

The script uses PHP. This has been tested in PHP v4x and above, but it should work in any PHP environment. The script is an adaptation used on Drupal 4.5 / 6. It is untested in 4.7 and may require a few tweaks.

5. Files Included

A list of the files included in this module. Please ensure that files are uploaded to the correct location.

settings.php
Modifications only to this file 5.1
themes [directory] 5.2
  • mhtml - directory containing page.tpl.php for mobile devices
  • imode - directory containing page.tpl.php for imode web browsers
  • wml - directory containing page.tpl.php wap compatible template
detect [directory]
  • browser.php - device detection script
  • browser.inc - text file containing list of all known mobile devices
  • fix_code.php - includes functions for tidying up final output

5.1 Directories within sites dependant on site set up
5.2 Screenshots, CSS, icons and additional templates can be added as required

6. Usage

Upload the detect directory to chosen location, then edit paths in settings.php accordingly. To use multisites, please see configuration for more details.

7. Code

The actual code in more detail.

Changes to settings.php set some header parameters that must be set before any content is sent to the browser. Drupal has a couple of built in headers that need to be overridden. Changes are therefore required to a couple of lines in common.inc.

// common.inc line 60
function drupal_get_html_head() {
  global $base_url;
 
  $output = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
  $output .= "<base href=\"$base_url/\" />\n";
  $output .= theme('stylesheet_import', 'misc/drupal.css');
 
  return $output . drupal_set_html_head();
}
 
// common.inc line 1875
drupal_set_header('Content-Type: text/html; charset=utf-8');

Change to the following. This overrides the default Content-Type. Note that if roll-back is required, common.inc must be reverted also.

// common.inc line 60
function drupal_get_html_head() { 
  global $output; 
  return $output . drupal_set_html_head();
 
 
// common.inc line 1875
#drupal_set_header('Content-Type: text/html; charset=utf-8');

7.1 settings.php

Towards the bottom of settings.php include the main file browser.php. Call the function and make some changes accordingly.

function html_fix($buffer) {
  return (preg_replace("!\s*/>!", ">", $buffer));
}
 
$accept = array(
        "xhtml" => "application/xhtml+xml",
        "html"  => "text/html",
        "wml"   => "text/vnd.wap.wml",  
        "mhtml" => "application/vnd.wap.xhtml+xml",
);
 
$mobi = array("chtml", "wml", "mhtml");
 
DEFINE ('DETECT_PATH', '/path/to/detect_directory/'); // change to suit
 
include_once   DETECT_PATH .'browser.php';
$browserfile = DETECT_PATH .'browser.inc';
$fixfile     = DETECT_PATH .'fix_code.php';
 
$or = FALSE; // Options: FALSE or keys from $accept
$detect = media_type($accept, $browserfile, $or);
 
if ((defined('MOBI') AND MOBI == true) OR in_array($detect, $mobi)) {
  $is_mobi = true;
}
else {
  $is_mobi = false; 
}

browser.php should return a key from the $accept array. $or enables complete override of the detection. This is site wide, so if $or = &#39;wml&#39;; the whole site will be in wml. Paths to files should be amended also. The next snippet sets http headers and then detects if the device is a mobile and restricts the number of snippets view on the main node page.

drupal_set_header('Content-Type: '. $accept[$detect] .'; charset=utf-8');
drupal_set_header('Vary: Accept');
 
if ($is_mobi == true) {
  $conf['default_nodes_main'] = 2;
  $conf['anonymous']   = 'Mobile User';
}

The final part of the script sets additional headers and then automatically selects a template dependent of device.

$default_css = 'misc/drupal.css'; // default drupal style
if ($detect == 'wml') {
  drupal_set_header('Content-Type: '. $accept[$detect] .', true');
  include $fixfile; // extra file for stripping out non-wml syntax
  ob_start('fix_code');
  $conf['theme_custom']  = 'wap'; // change to suit
  $conf['theme_default'] = 'wap'; // change to suit
  $output = '';
}
elseif ($detect == 'mhtml') {
  $conf['theme_custom']  = 'mobi'; // change to suit
  $conf['theme_default'] = 'mobi'; // change to suit
  $output  = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8" />'."\n";
  $output .= '<base href="'. $base_url .'/" />'."\n";
  $output .= theme('stylesheet_import', $default_css);
elseif ($detect == 'chtml') {
  $conf['theme_custom']  = 'imode'; // change to suit
  $conf['theme_default'] = 'imode'; // change to suit
  ob_start('html_fix');
  $output  = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8">'."\n";
  $output .= '<base href="'. $base_url .'/" />'."\n";
  $output .= theme('stylesheet_import', $default_css);
elseif ($detect == 'xhtml' AND $is_mobi == true) {
  $conf['theme_custom']  = 'mobi'; // change to suit
  $conf['theme_default'] = 'mobi'; // change to suit
  $output  = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8" />'."\n";
  $output .= '<base href="'. $base_url .'/" />'."\n";
  $output .= theme('stylesheet_import', $default_css);
}
elseif ($detect == 'html') {
  ob_start('html_fix'); 
  $output  = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8">'."\n";
  $output .= '<base href="'. $base_url .'/" />'."\n";
  $output .= theme('stylesheet_import', $default_css);
}
else {
  $output  = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8" />'."\n";
  $output .= '<base href="'. $base_url .'/" />'."\n";
  $output .= theme('stylesheet_import', $default_css);
}

7.2 Themes

Themes are made using phptemplate for Drupal. They work as any other template. However, they render content slightly differently using different DTDs according to device capability. Some examples are listed below.

wml 7.1
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card cardid="content" cardtitle="<?php print $site_name; ?>">
<?php if ($title)  ?><p><big><?php print $title; ?></big></p><?php  ?>
<?php if ($site_slogan)  ?><p><em><?php print $site_slogan; ?></em></p><?php  ?>
<?php print $content; ?>
<p><a href="http://mobiforge.com/#menu">Menu</a></p>
</card>
<card cardid="menu" cardtitle="Menu">
  <?php if (isset($primary_links)) { ?>
    <p><?php print theme('links', $primary_links) ?></p>
  <?php } ?>
</card>
</wml>
mhtml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" 
"http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $language ?>" xml:lang="<?php print $language ?>">
<head>
  <title><?php print $head_title ?></title>
<link rel="Home" href="/" title="Network Home" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />  
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <?php print $head ?>
  <?php print $styles ?>
</head>
 
<body>
 
  <div id="home">
    <?php if ($logo) : ?>
      <a accesskey="1" href="<?php print $base_path ?>" 
      title="<?php print t('Home') ?>"><img src="<?php print($logo) ?>" 
      alt="<?php print t('Home') ?>" border="0" /></a>
    <?php endif; ?>
  </div>
  <?php if ($site_name) : ?>
    <div class="site-name"><a href="<?php print $base_path ?>" 
      title="<?php print t('Home') ?>"><?php print($site_name) ?></a></div>
    <?php endif;?>
 
    <?php if ($site_slogan) : ?>
      <div class="site-slogan"><?php print($site_slogan) ?></div>
    <?php endif;?>
 
    <?php if (isset($primary_links)) { ?>
      <p><?php print theme('links', $primary_links) ?></p>
    <?php } ?>
 
    <?php if (isset($secondary_links)) { ?>
      <p><?php print theme('links', $secondary_links) ?></p>
    <?php } ?>
 
    <?php print $content; ?>
 
    <?php if ($sidebar_left != ""): ?>
      <div id="sidebar-left">
        <?php print $sidebar_left ?>
      </div>
    <?php endif; ?>      
 
  <?php if ($footer_message) : ?>
    <div id="footer-message">
      <p><?php print $footer_message;?></p>
    </div>
  <?php endif; ?>
 
</body>
</html>

These are stripped down versions of phptemplate. Some variables, that are unnecessary for a mobile device, have been removed. imode's template is similar, except it is written in Compact HTML. xhtml and html are fully-blown templates, written in xhtml and html respectively, and are targeted for non-handheld devices.

7.1 Note that cardid and cardtitle are deliberately incorrect here. fix_code.php corrects these later.

7.3 Detect

The main file is browser.php. This returns best suited $_SERVER[&quot;HTTP_ACCEPT&quot;] and whether it is a hand-held device or not checking against $_SERVER[&quot;HTTP_USER_AGENT&quot;]. This can be adapted to be a stand-alone script, but it has dependencies.

$accept
An array equivalent to the following, containing content-types.
$accept = array(
  "xhtml" => "application/xhtml+xml",
  "html"  => "text/html",
  "wml"   => "text/vnd.wap.wml",  
  "mhtml" => "application/vnd.wap.xhtml+xml"
);
The array key is straight forward, the array value is the full accept_type. This is used subsequently used in drupal_set_html_head() and drupal_set_header() respectively.
$browserlist
This creates an array using file() to open browser.inc. Contained in browser.inc is a list of the first four characters of the user_agent string of known devices. Each device is listed on a new line. Extract below.
alav
alca
armv
au-m

Having created the 2 arrays listed above, the script now starts to check the $_SERVER[&quot;HTTP_ACCEPT&quot;], including q value, so if the device accepts more than one mime type, the script should pick the best one. If there is no q value but $accept is there then 1 is added.

function media_type(&$accept, $browserfile, $mime = false) {
  $is_mobi = false; // note: this variable only exists within this function
  if ( $mime !== false ) {
    return $mime;
  }
  elseif (stristr($_SERVER["HTTP_USER_AGENT"],"W3C_Validator")) {
    return $mime = 'xhtml';
  }
  elseif (!isset($_SERVER["HTTP_ACCEPT"])) {
    return $mime = 'html';
  }
  else {
    $mime = 'html';
 
    $c = array();    
 
    foreach ($accept AS $mime_lang => $mime_type) {
      $esc_type = '/'. str_replace( array ('/','.','+'), array('\/','\.','\+'), $mime_type) .";q=0(\.[1-9]+)/i";
      $c[$mime_lang] = 1;
      if ( stristr($_SERVER["HTTP_ACCEPT"], $mime_type) ) {
        $c[$mime_lang] = $c[$mime_lang] + 1;
      }
      if (preg_match($esc_type, $_SERVER["HTTP_ACCEPT"],$matches)) {
        $c[$mime_lang] = $c[$mime_lang] - (float)$matches[1];
      }
 
    $iMode = array('doco', 'j-pho', 'up.b', 'ddip', 'port');
 
    if (in_array(strtolower(substr(trim($_SERVER['HTTP_USER_AGENT']),0,4)), $iMode)) {
      $mime    = 'chtml';
      $is_mobi = true;
    }
    else {
      arsort ($c,  SORT_NUMERIC);
 
      /* The aim is to reduce $c to one element, the best suited accept_type */
 
      if ( array_sum($c) == count($c) ) {
        unset ( $c );
        $c['html'] = 1;    
      }
 
      $max = max($c);
      foreach ($c as $type => $val) {
        if ($val != $max)  unset ( $c[$type] ); 
      }
 
      $browsers = file($browserfile);
      foreach ($browsers as $dev)  $browserlist [] = trim($dev);     
 
      if (in_array(strtolower(substr(trim($_SERVER['HTTP_USER_AGENT']),0,4)), $browserlist))  $is_mobi  = 1; 
 
      if ( array_key_exists('xhtml', $c) ) {unset ( $c ); $c['xhtml'] = 1;}         
      if ( array_key_exists('html', $c) ) {unset ( $c ); $c['html'] = 1;}                
      if ( array_key_exists('wml', $c) )  {unset ( $c ); $c['wml'] = 1;}     
      if ( array_key_exists('mhtml', $c))  {unset ( $c ); $c['mhtml'] = 1;}
 
      $mime = key($c);
    }
 
    define ('MOBI', $is_mobi);
    return $mime;
  }
}
The output for Firefox with application/vnd.wap.xhtml+xml and text/vnd.wap.wml added would be something follows if the code was debugged.
Array
(
    [xhtml] => 2
    [html] => 1.1
    [wml] => 1.4
    [mhtml] => 2
)

For Firefox the final result should be xhtml and MOBI = false.

8. Configuration

fix_code.php is a file containing a similar function to html_fix(). It strips out all non-wml syntax using preg_replace and str_replace and is called when ob_start is called. Information about this file has been included here as it should be edited further to strip out any additional content that is not required.

Brief details on how to use these files were outlined here, additional information follows.

One site serving multiple devices using one code base

  1. Upload all files
  2. Log in as an administrator and enable all the uploaded templates
  3. Make the required changes to common.inc
  4. Amend the settings.php file in sites/default directory as detailed previously

Multisites using one code base

For more information on how to set up multisites with Drupal, please visit: instructions or overview.

  1. Upload all files
  2. Log in as an administrator and enable all the uploaded templates
  3. Make the required changes to common.inc
  4. Amend the settings.php file in sites/<b>device_name</b> directory specifying the $or to match the device of choice 8.1

8.1 The whole detection script does not need to be included in settings.php if the device type is know. Below is an example for WAP / WML site.

 
DEFINE ('DETECT_PATH', '/path/to/detect_directory/'); // change to suit
 
$fixfile = DETECT_PATH .'fix_code.php';
drupal_set_header('Content-Type: text/vnd.wap.wml; charset=utf-8');
drupal_set_header('Vary: Accept');
 
$conf['default_nodes_main'] = 2;
$conf['anonymous']   = 'Mobile User';
drupal_set_header('Content-Type: text/vnd.wap.wml, true');
include $fixfile; // extra file for stripping out non-wml syntax
ob_start('fix_code');
$conf['theme_custom']  = 'wap'; // change to suit
$conf['theme_default'] = 'wap'; // change to suit
$output = '';

9. Summary

This article utilizes a simple device detection script and selects the relevant output. Further changes may be needed to strip out irrelevant content for mobile devices, most of which can be achieved by editing fix_code.php.

10. References and additional information

References and additional information.

Status

This document is draft. Development work has progressed to create a module to include this functionality. Files can be downloaded in zip format here.

References and Credits

Comments

Send comments or queries here

Additional

Working example of this script can be seen at http://www.227net.com. Please note that due to limitation in sending XHTML with the correct content-type XHTML compatible browser still receive content as text/html. Multisites have also been enabled. Device dependant sites are listed below:

AttachmentSize
files.zip4.78 KB

Posted by admin - 18 Jan 2007

admin's picture

mobiForge administrator

Posted by thetoast 7 years ago

Just wanted to say I've been looking for a good website with resources for mobile development and this is by far the best. Thanks guys :
-) I'' be looking into this tutorial carefully as I am a drupal developer so hopefully I'll be able to give some feedback soon. Again, many thanks.

Drupal developer

Drupal developer

Posted by awidarto 7 years ago

This is a great article i've been searching for days... Tried it but not workin on my Drupal5.1 installation, I know that this is only tested on 4.5 / 6 , but then what is the necessary tweak for 5.1 ?
Seems that the way 5.1 doing the bootstrap sequence is the problem ...

Thanks for great article anyway... :)

Posted by jabba_29 7 years ago

The module will be available for Drupal 5.1x very soon. New and improved for 4.7x too.
Working versions are available on sites mentioned above and 5.1x @ http://www.skiffie.com

Stay tuned..

---------------------------------------------------------------
- Let the might of your compassion arise to bring a quick end -
- to the flowing stream of the blood and tears ..... -
----------------------------------------------------------

Posted by jabba_29 6 years ago

The accessibility module can now be downloaded from the project pages: http://drupal.org/project/accessibility
Drupal 4.7 users can get the relevant files from my site: drupal accessibility module

Jamie

---------------------------------------------------------------
- Let the might of your compassion arise to bring a quick end -
- to the flowing stream of the blood and tears ..... -
----------------------------------------------------------

Posted by rahul2435 7 years ago

this is a gr8 script, but i was wondering if someone could clarify
something for me, im new to mobile content serving,

between practices and conventions,
this script does not seem to follow RFC 2616 Sec - 14
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

where in the script we are subtracting q value from 2, RFC says its the q value itself.

if we get

mhtml, xhtml;q=.8, wml;q=.5,

according to the RFC we should serve mhtml,

but checking with the script above we get

mhtml;q=2, xhtml;q=1.2, wml;q=1.5,

should we go by the RFC or the above is the normal followed practice.

Posted by jabba_29 6 years ago

if we get
mhtml, xhtml;q=.8, wml;q=.5,
according to the RFC we should serve mhtml,
but checking with the script above we get
mhtml;q=2, xhtml;q=1.2, wml;q=1.5,
should we go by the RFC or the above is the normal followed practice.

That means that the script should still use mhtml.
Adding 1 at the beginning was only meant to simplify the maths -
so there would be no negative numbers.

---------------------------------------------------------------
- Let the might of your compassion arise to bring a quick end -
- to the flowing stream of the blood and tears ..... -
----------------------------------------------------------

Posted by tripollr 6 years ago

Hi,

I'm quite new on Drupal, And after reading all this material I'm wondering about how to integrate more extended device detection capabilities based on a Device DB such as Wurfl. Thus, it would allow to format pages more suited to device characteristics (screen size, scripting languages, etc.).

Do anybody have any experience on this or can direct me to some suitable resources?

Kind regards,

Toni

Posted by MobilePublisher 6 years ago

Dear Toni / tripollr,

I've just finished writing a short-news in the m-zine MobilePublisher about the new version 6.0 of Drupal. MobilePublisher uses Drupal as well (in the background, as a CMS/CMF), just like you !

NOW --> Have you heard about dotMobi's DeviceAtlas? It is a NEW tool and DATABASE, which provides accurate information about attributes of mobile devices. The positive thing about it: It's free for members of the dev.mobi-developer-forum/community. I am checking/verifying DeviceAtlas at the moment, that's why I cannot give you any further information. I hope this was useful!

Best regards,
Philipp Schaffner

Posted by tripoll 6 years ago

Hi Philipp,

Thanks for your hints, although my german knowlegdge is too bad to read your short-news.

In any case I've been looking for information about MobilePublisher and I'm going to intall and try it.

Also, I've would test DeviceAtlas in order to check its usefulness, specially regarding elder devices which are still being used by people. Any valorations from other people would be welcome.

Regards,

Toni Ripoll
ADSMEDIA CTO

Toni Ripoll ADSMEDIA CTO

Posted by majorsoft 6 years ago

Hi All,

sorry about the cross posts.. trying to make sure i speak to the right poeple...

I have a weekend project to enable a web site to support downloading of j2me files.
I had a joomla developer doing this for me but he has ‘walked’ and now I urgently need to set this up.
I was thinking Joomla 1.5 but happy to take advice.
I want to be able to make available about 15 [or more] separate j2me programs – each one has 10 versions depending on phone screen size.
I want to be able to enable the user to select a file they want – then add their phone number to then push/send an SMS with the link to the users phone.
The user opens the link which takes them to a download page where the device type is detected and based on the screen size – the user is provided a download link.
It is a bit like a shopping cart – but delivery is via SMS link.
Is Joomla the best CMS to use?
Has anyone done this with SMS?
Is there a turnkey solution for mobile deployment of content?
Would anyone be prepared to assist me?
I have read the various articles on this excellent site – I just need some hand holding / good advice / assistance.
Thx all.

Major

Posted by tom@mobiledrupal.com 5 years ago

Hi,

I’ve recently started a blog, mobiledrupal.com, which all about making and testing mobile websites with Drupal. I’ve also added a section which summarises mobile modules available for Drupal, which I hope people will find helpul.

Please have a look and get in touch with any comments!

Tom