jeudi 25 Nov 2010

Détection des mobiles, un meilleur code PHP!

PHPEn cherchant comment détecter les téléphones portables et autres petits appareils pour faire des versions pour mobiles de mes sites web, je suis tombé plusieurs fois sur un code PHP vraiment très mauvais! :-o

Il y a même une entreprise spécialisée dans la création de sites mobiles qui m'a envoyé ce code à utiliser sur le site d'un client. J'ai donc utilisé cette base pour réécrire un code beaucoup plus propre et plus rapide!

~

Le code "incriminé" est visible sur Mobiforge.

Pourquoi est-il mauvais? Parce qu'il est composé de 5 tests visant à détecter si l'agent utilisateur ($_SERVER['HTTP_USER_AGENT'] en PHP) est celui d'un navigateur pour mobile ou d'un navigateur standard. Or ces 5 tests sont systématiquement effectués.

Même si PHP a déjà découvert qu'il a à faire à un mobile, il continue d'exécuter les autres tests! Surtout que le 1er test utilise preg_match, il est très puissant et détecte 99% des mobiles. Il serait donc inutile de continuer!

Dans le même style DetectMobileBrowsers propose un code très complet. Il s'arrête bien dès qu'on est sûr d'avoir un mobile, mais les tests sont lourds (utilisant preg_match!) et dans le pire des cas (ordinateur normal), il effectue 11 tests pour aboutir! Si vous n'avez pas besoin de la précision qu'il apporte, regardez plutôt le mien. ;-)

~

Voilà mon code:


function détection_mobile ()
{
	if (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE']))
		return true;

	if (isset ($_SERVER['HTTP_ACCEPT']))
	{
		$accept = strtolower($_SERVER['HTTP_ACCEPT']);
		if (strpos($accept, 'wap') !== false)
			return true;
	}

	if (isset ($_SERVER['HTTP_USER_AGENT']))
	{
		if (strpos ($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false)
			return true;

		if (strpos ($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false)
			return true;
	}

	return false;
}

Je met en premier le test simple, pour sortir avec le moins de traitement possible de la fonction. Dans le pire des cas, on ne fait que 3 tests vraiment beaucoup plus simple que ceux à base de preg_match!

Ce test fonctionne avec le navigateur par défaut d'Androïd, Safari pour iPhone, Opera Mini et Mobile, les navigateurs Wap, les robots version mobiles de Google (je ne sais pas comment tester les autres moteurs de recherche). Si vous avez un navigateur mobile qui n'est pas détecté, je serais heureux de le savoir. ;-)

~

Si vraiment vous voulez être certains, vous pouvez rajouter un dernier test dans la boucle if (isset ($_SERVER['HTTP_USER_AGENT'])):


if (preg_match('#Android|BlackBerry|Cellphone|iPhone|iPod|hiptop|HTC|MIDP-2\.|MMEF20|MOT-V|NetFront|Newt|Nintendo Wii|Nintendo DS|Nitro|Nokia|Opera Mobi|Palm|PlayStation Portable|PSP|portalmmm|SonyEricsson|Symbian|UP.Browser|UP.Link|webOS|Windows CE|WinWAP|YahooSeeker/M1A1-R2D2|LGE VX|Maemo|phone#', $_SERVER['HTTP_USER_AGENT']))
  return true;

~

Ensuite pour utiliser ce code, on peut simplement envoyer un CSS modifié pour s'adapter aux mobiles. Cela me parait une meilleure solution que d'avoir deux sites avec deux adresses différentes, mais le même contenu!


if (détection_mobile())
  echo '<link rel="stylesheet" type="text/css" href="style/version-mobile.css" />
<meta name="HandheldFriendly" content="true" /> (obsolète)
<meta name="viewport" content="width=device-width" /> (peut être mis en version bureau aussi) ';

Comme ça, vous voyez aussi les meta que j'utilise sur les versions téléphones portables (qui ne bloquent pas le zoom comme le font certains sites, même gros!). Plus d'informations sur les meta pour les mobiles sur Learn the Mobile Web.

~

Idéalement il faut rajouter un lien/formulaire pour passer de la version bureau à la version mobile, en cas d'erreur ou simplement pour un utilisateur qui préfère l'autre version. C'est pour cette raison que j'utilise une session pour garder les préférences de l'utilisateur.

On peut aussi basculer instantanément d'une version à l'autre, même en gardant la préférence avec un cookie, en utilisant Javascript. Voir un exemple sur cette page, le menu thème en bas à droite change le CSS instantanément en gardant le choix dans un cookie créé en Javascript. J'explique cette méthode dans l'article suivant changer le style en Javascript. Le bon raisonnement est de proposer le style CSS mobile, sans l'imposer. :-)


MàJ: Aujourd'hui, l'apparition des requêtes médias dans CSS 3 qui permettent d'adapter le CSS à la taille de l'écran, rend un peu obsolète de créer 2 fichiers de style. Il vaut mieux adapter le CSS principal à tous les formats, ce que je fais désormais sur ce site et d'autres.


café Cet article vous a aidé? 
Offrez-moi un café!
Agrégateur informatique

24 réponses à “Détection des mobiles, un meilleur code PHP!”

  1. 1
    Comparateur auto (carwego.com) a dit:

    Merci pour ce snippet ! On pourrait meme pousser le vice à detecter les différentes versions des mobiles ( dans un switch ) genre :
    switch(true){

    case (preg_match('/ipod/i',$user_agent)||preg_match('/iphone/i',$user_agent)); //iPhone or iPod
    $mobile_browser = true;
    $mobile_browser_type = "1"; //Smart Phone
    break;

    case (preg_match('/android/i',$user_agent)); //Android
    $mobile_browser = true;
    $mobile_browser_type = "1"; //Smart Phone
    break;
    .............

    }

    et sortir une version optimisée pour chaque famille de téléphone. Par exemple en supprimant le flash pour les iphones.

  2. 2
    David (azur-dev.kizone.net) a dit:

    C'est ce que fait DetectMobileBrowsers, mais du coup c'est beaucoup plus lourd, ça en devient difficile de le faire à chaque visite d'une page. :-|

    Puis cela va à l'encontre des recommandations du W3C de fournir du contenu différent par navigateur. Je suppose que les iPhone savent lire le contenu alternatif au Flash, et qui sait un jour, ça changera peut-être...

    L'idéal serait de simplement utiliser la règle media des CSS mais aucune ne permet de distinguer les mobiles actuels.

  3. Rétrolien de Tweets that mention Détection des mobiles, un meilleur code PHP! - HTML & CSS - Azur Dev -- Topsy.com
  4. 3
    Hervé a dit:

    Je me permets de te suggérer d'aller voir ce site/projet :
    http://www.tera-wurfl.com/

    Franchement, on n'a pas fait mieux

  5. 4
    David (azur-dev.kizone.net) a dit:

    Oui mais si j'ai bien compris il sert à détecter précisément l'appareil, et je pourrais faire la même remarque que précédemment. C'est le contraire du code standard auquel nous aspirons tous! ;-)

  6. 5
    Hervé a dit:

    regardes de plus prêt, il dispose d'une méthode simple permettant de savoir si on est "face" à un mobile

  7. 6
    Jérémy a dit:

    Tu ne peux pas fournir le même code "HTML" à un mobile qui ne sait lire que le WAP et à un Browser NextGen compatible HTML 5...

  8. 7
    David (azur-dev.kizone.net) a dit:

    Hervé, je ne vois pas l'intérêt d'utiliser un truc d'1Mo (difficile d'accès qui plus est) pour tester si on a un mobile alors que mes 10 lignes le font. C'était le but de cet article, avoir un code simple pour décider quel CSS envoyer (+ quelques entêtes).

    Jérémy, je ne connais pas WAP, pour moi c'est même déjà mort. Par "Browser NextGen compatible HTML 5" si tu entends navigateur mobile genre Safari, Opera Mobile, celui d'Androïd... c'est de ceux-là dont on parle.

    Ce n'était qu'un code modèle, optimisé au maximum, correspondant aux besoins de 99% des webmasters. Le gars qui a su se prendre la tête à apprendre WAP saura chercher lui-même comment détecter les portables d'avant 1960 pour leur envoyer! :-p

  9. Rétrolien de Activer le style mobile en Javascript - HTML & CSS - Azur Dev
  10. 8
    Ludovic a dit:

    Bonjour,

    Je viens d'essayer votre script il marche parfaitement sur le gsm "samsung star" et le "htc legend". Par contre il ne semble pas fonctionner sur le "htc touch".

    Il semble que windows mobile fasse encore des siennes...

    Ludovic

  11. 9
    Hervé a dit:

    "je ne vois pas l'intérêt d'utiliser un truc d'1Mo (difficile d'accès qui plus est) pour tester si on a un mobile alors que mes 10 lignes le font"
    Syndrome du "not invented here" ;-)

    Qui amène à ce genre de remarque :
    "Par contre il ne semble pas fonctionner sur le "htc touch"."

  12. 10
    David (azur-dev.kizone.net) a dit:

    Tu veux dire qu'on est toujours plus fier de ce qu'on a créé? Oui, normal. ;-)

    Je viens de chercher pour Windows Mobile "Windows CE" est commun à toutes les versions dans le "user agent". Il suffit de rajouter ce test, je le rajoute dans le code principal, toutefois, il était déjà dans le dernier test facultatif.

    Même en le rajoutant ça reste beaucoup plus léger et beaucoup plus performant. Même en rajoutant 50 tests ça le resterait! :-p

    Comme j'ai écrit dans l'article suivant: Comme toujours sur Azur Dev, ceci n'est qu'une inspiration pour d'autres développeurs. Ce n'est ni un tutoriel, ni un code à copier-coller bêtement! ;-)

  13. 11
    Ludovic a dit:

    Bonjour,

    Merci pour la réponse rapide! Et merci pour le partage de savoir je préfère avoir un script plus performant qu'une regex de 5km :P

    J'avais fait un script dans le style avec plus de strpos

    "
    //os
    symbianos
    android
    // navigateur mobile
    windows ce
    opera mini
    mazingo
    t68
    syncalot
    blazer
    mobile
    // wap
    WAP2.0
    // marque
    blackberry
    lg-,lg/
    mot-
    nokia
    palm
    samsung
    sonyericsson
    "

    C'était un code sans prétention faite à partir des listes des users agents trouvé. Je peux te l'envoyer si tu veux.

    A bientôt

  14. 12
    Ludovic a dit:

    Bonjour,

    Pour info, le HTC Touch utilise opera (ce qui est pas plus mal) avec comme user agent "HTC_P3700 Opera/9.50"

    Donc un petit rajout de

    if (strpos ($_SERVER['HTTP_USER_AGENT'], 'HTC') !== false)
    return true;

  15. 13
    David (azur-dev.kizone.net) a dit:

    Ah merci, donc le "Windows CE" ne sert à rien pour lui... HTC est une bonne chaine à rajouter en effet. :-) (Bizarre qu'il utilise Opera normal et pas le Mini ou Mobile.)

  16. 14
    Eric a dit:

    Bonjour,

    Le(s) USER_AGENT de IE est (sont): Internet Explorer Mobile or IE Mobile (voir ici)

    Sinon, merci pour le code et les conseils (une petite erreur générant un warning du parser php: Compilation failed: .....etc. = une parenthèse de trop en fin de liste)
    Merci à toi!

  17. 15
    mimi15 a dit:

    bonjour!!

    Tout d'abord merci pour ce tuto qui m'aide beaucoup :)
    Cependant je ne comprends pas bien où tu dois placer le bout de code qui sert à rediriger vers un autre css s'il s'agit d'un mobile ?

    Dsl s'il s'agit d'une question con ....

    Merci!

  18. 16
    David (azur-dev.kizone.net) a dit:

    C'est le dernier cadre de code. Si c'est un mobile, on envoie quelques entêtes et le CSS dédié aux mobiles.

    Le mettre en session est facultatif, c'est juste si on veut offrir la possibilité de changer. Chose que je fais plutôt en Javascript comme sur ce site. ;-)

  19. Rétrolien de Détection des appareils mobiles | Code Mac Miller
  20. 17
    dab653 (atomicdab.tk) a dit:

    Salut,
    ton code est très bon, merci, mais il pourrait être 1000 fois simplifié comme ceci :
    function isMobile() {
    return (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE']) || (isset($_SERVER['HTTP_ACCEPT'])&&strpos(strtolower($_SERVER['HTTP_ACCEPT']), 'wap') !== false) || (isset($_SERVER['HTTP_USER_AGENT'])&&(strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false)));
    }
    Cord.
    dab653

  21. 18
    carine57 a dit:

    bonjour à tous

    je ne métrise pas beaucoup le sujet donc quelqu'un pourrait il m'aider pour avoir le script mais en utilisant une redirection vers une autre version et surtout ou placer tout ça dans une page

    autre chose cela marche t'il quant on arrive sur le site par une autre page ou faut il mettre le script sur toutes les pages

    merci de votre aide

  22. 19
    Eymer (jceymer.free.fr) a dit:

    Bonjour,
    Le preg_match donné ne fonctionne pas !...
    preg_match() [function.preg-match]: Compilation failed: unmatched parentheses at offset 280
    Où serait l'erreur?
    Merci
    if (preg_match('#Android|BlackBerry|Cellphone|iPhone|iPod|hiptop|HTC|MIDP-2\.|MMEF20|MOT-V|NetFront|Newt|Nintendo Wii|Nintendo DS|Nitro|Nokia|Opera Mobi|Palm|PlayStation Portable|PSP|portalmmm|SonyEricsson|Symbian|UP.Browser|UP.Link|webOS|Windows CE|WinWAP|YahooSeeker/M1A1-R2D2|LGE VX|Maemo|phone)#', $_SERVER['HTTP_USER_AGENT']))
    return true;

  23. 20
    David (azur-dev.kizone.net) a dit:

    En effet, il y a une parenthèse en trop à la fin après "phone". Je corrige dans l'article. ;-)

  24. 21
    sivmatt (compressor-fic.com) a dit:

    connecté via mobile samsung android avec firefox
    merci pour la fonction

Laisser un commentaire

Azur Dev