REWRITE
I have a website written in HTML5, and the same website written in XHTML. I would like to render one or the other based on whether or not someone is using a browser that supports some of the most basic features of HTML5.
NOTE
The site does not use the canvas, audio, or video features of HTML5. It is simply tagged with aside, section, nav, etc, and uses some of CSS3's fun features for styling embellishments. The difference between the HTML5 site and the XHTML site is minimal, and probably will be barely noticeable to anyone if I can make this work. The content is the same, it is just presented slightly differently.
THE REASON I DID IT THIS WAY
Once the dinosaur browsers are gone, I am hoping I can simply post the HTML5 site, and do away with the old XHTML.
I am running into some logistical snags and have not fully formulated how I want to go about this. I initially had the idea to use Javascript conditional statements to determine which PHP include to render. Yes, go ahead and laugh, I probably will some day too. While investigating that, a person commented that XML might make that possible. I am fairly capable with Javascript, PHP and XML. This is the first time I have tried to integrate Javascript with PHP, so now I understand why my original plan needed some more work.
Ultimately, I feel pretty strongly that this is how I want to move forward. I read about progressive enhancement versus graceful degradation, but I have decided that I want to give my client a beautiful website using all of the new semantic tags and simple style selectors to increase SEO and guarantee that when HTML4 goes away, this new site will stand the test of time...at least for a little while.
If you strongly object to this method, I am willing to listen to what you have to say. Please share your thoughts either way.
What you ask for is impossible; as I already explained, PHP is server-side, and JS is client-side; anything done php side is finished by the time the page is delivered to the user, so it is impossible for js to influence the php side unless your site, or content delivery, is done completely in ajax, which is a method of using js and php to retrieve information; in short, js sends a request to another php page on your server and returns the result.
That however is much more complicated, and I do not recommend it until you are more familiar with both JS and PHP.
That aside, however, there is a solution in php, although I do not have the complete code right now.
The solution is the php 4 and 5 function of get_browser():
$arr = get_browser(null, true);
$var = "some browser";
if ($arr['parent'] == $var) {
require('/php/file.php');
}
else {
//etc
}
The above is before your answer update; I have nothing else to say in regards to said update.
Update: In regards one of the comments below in regards to ajax, I will attempt.. an example. I won't attempt to call it 'simple', because ajax is anything but.. though back to the point...
HTML:
<html>
<body>
<div id="main_body">
</div>
</body>
</html>
JS:
//some code to determine user-agent/browser, set variable 'agent' with result
var use_html5;
if (agent == browser) {
use_html5 = 'yes'
}
else {
use_html5 = 'no'
}
function retrv_body() {
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else {// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {//readState 4 is when the request has finished;
//0: request not initialized
//1: server connection established
//2: request received
//3: processing request
//4: request finished and response is ready
document.getElementById('main_body').innerHTML = xmlhttp.responseText;
//set html of div with id 'main_body' to rendering retrieved from php_file_in_same_dir.php
}
}
xmlhttp.open("POST","php_file_in_same_dir.php",true);
//set type of form, boolean is in regards to whether the request is asynchronus or synchronous
//most ajax requests are async, which means they themselves finish executing usually after the function itself has run. I'm not truly knowledgeable regarding this specific thing since I've only ever used async requests, though I would assume being a sync request would mean the function actually waits until it returns a value before it finishes executing.
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//set the headers of the content.
xmlhttp.send("html5=" + use_html5);
//finally, send the data. Depending on the data, the data may need to be url-encoded.
}
retrv_body();
PHP:
<?php
if ($_POST['html5'] == 'yes') {
include('body5.php');
}
else {
include('body_other.php');
}
//body generating code, render page.
?>
The above is just an example, and I would not recommend actually using it, save the retrv_body() function, and changing it into something you can really use.
Hopefully the comments I've put in the code will help in understanding; if anything is left to question, feel free to ask that I explain more thoroughly.
No.No.No.No.No!
Two points:
Use HTML5 shiv - Gives older IE browsers HTML5 capabilities)
Progressive enhancement - You shouldn't code for different browsers. Your code should work in all browsers. Then add features that enhance, but are not required for the site to function, the user experience.
Related
Reasoning for this Question
I am aware that browser detection can never be 100% reliable as the User Agent header can always be forged, however, I am not bothered by this.
Although there are many questions on this topic, they all seem to be quite old, so to get an up to date answer I felt I should ask this question again.
I am currently detecting the browser name and version server side using the PHP browscap, and then returning the name and version into javascript variables (not a very good method). The reason why I need to do this is simply to display a message to visitors if they are not using a supported browser.
Current method (something similar):
<script type="text/javascript">
var browser = new Array();
browser['browser'] = '<?php echo $browser_name; ?>';
browser['version'] = '<?php echo $browser_version; ?>';
browser['error'] = '<?php echo $browser_error; ?>';
</script>
It would be much better to do this client side as the browscap can be quite slow, and it would prevent me having to pass values into javascript variables from PHP. If you think using PHP is a better method then please state in your answer, this is just my opinion.
Question
Therefore, my question quite simply, is the following link a reliable method for determining the browser name and version?
Javascript Detect
I am aware that new browsers will need to be added to this, this does not bother me. I am more concerned about whether the algorithm used is reliable.
Thanks in advance
UPDATE 1
To see what I mean, take a look at https://www.icloud.com/ in Internet Explorer 7 or less. You will receive a message saying that the browser is not supported. This is easy to do for IE as you can simply use the <!--[if gt IE..., however, I need to test all browsers.
This does not look right, you can fetch browser information from Javascript. No need to mix JS and PHP code to do that.
You can do something like this to fetch, and detect user browser with just JavaScript:
var userAgent = navigator.userAgent.toLowerCase();
var old = false;
// Internet Explorer 7
if (userAgent.indexOf('msie 7.0b') !== -1) { old = true; }
else if (userAgent.indexOf('msie 7.0') !== -1) { old = true; }
// Internet Explorer 6
else if (userAgent.indexOf('msie 6.1') !== -1) { old = true; }
else if (userAgent.indexOf('msie 6.01') !== -1) { old = true; }
else if (userAgent.indexOf('msie 6.0b') !== -1) { old = true; }
else if (userAgent.indexOf('msie 6.0') !== -1) { old = true; }
...
// Detect any other browser versions you consider old
if(old = true) {
// Show notification and alert users that they are using old browser
}
This is how you can do it using JS, but you can also use HTML to achieve this:
<!--[if lte IE 6]>
// include your .css style or do whatever you want to alert users their browser is old
<![endif]-->
Short answer to your question is YES, its wrong to detect user browser the way you do it, since you can do it with plain JavaScript, or even with HTML. No need to mix PHP and JS code here, and at the end, both PHP and JS will get the same UserAgent info.
Explanation
After extensive research and discussing amongst other developers, it is clear that there is no reliable method for retrieving the browser name and version from the User Agent. This is down to several reasons:
The format of a browsers User Agent can change at any time if the developers of the browser so wish to do so. This could immediately prevent some scripts from working correctly.
Users can forge their User Agents to mimic other browsers, and therefore would appear to be using a browser they are not.
Possible Solutions
Whilst I hugely discourage the use of these scripts as they could stop working at the release of an update to any browser anytime, if you do wish to detect the browser name and version in Javascript then I would advise using this script:
Javascript Detect
However, the most reliable method for retrieving the details of the browser is without a doubt the browscap supplied by Gary Keith. The browscap project offers extensive information about each browser and OS gathered from the User Agent. It is very easy to implement and even easier to use. To read more, take a look at:
Gary Keith - Browscap
If you choose to use the browscap by Gary Keith, you will need to ensure it is updated weekly at the very least.
Answer
Whilst I am contradicting myself with this answer, it is clear that detecting the browser information with any sort of script is not advised. The only reliable method of browser detection is that of the Internet Explorer HTML conditions, and as stated, these only cover Internet Explorer.
Try to avoid browser specific functions and notices, and make use of the built in features such as:
media="only screen and (device-width: 768px)"
and
<!--[if IE 8]>I am IE 8<![endif]-->
This question needs an updated answer. I think the best option these days for client-side detection is WURFL.
Its an updated library of devices based on Useragents - think Browscap for the client side.
Load the JS and it returns JSON based on the device that requested the js. Perfect!
<script type="text/javascript" src="//wurfl.io/wurfl.js"></script>
Because it does the parsing on the WURFL server side, you need to load the js remotely and not save it in your dir tree.
A super easy
WURFL.is_mobile
is all it takes to determine mobile for example.
Good luck.
You could try having a look at navigator.appName and navigator.userAgent.
The yepnopejs IE detection (!ie prefixes) works by utilizing the MS conditional comments.
A short snippet for detecting versions of IE prior to IE10 in JavaScript without resorting to user-agent sniffing.
while (
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->'
);
// …
https://github.com/SlexAxton/yepnope.js/blob/master/prefixes/yepnope.ie-prefix.js
yepnope usage example:
yepnope({
load: ['normal.js', 'ie6!ie7!ie-patch.js'] // patch for ie6 or ie7 only
});
You can use a perfect plugin for this information written in jQuery (like javascript)
look at this link:
https://github.com/jquery/plugins.jquery.com
Be sure to do feature detection instead of browser detection when you want to determine if a certain feature is available in a browser, apply bugfixes, etc.
I have a script that works fine in all browsers except ie6 (including ie7 and ie8).
Is there any semi reliable way I can exclude this nefarious browser.
I've tried this:
<!--[if !IE 6]>
<?php include("fconditionals.php"); ?>
<![endif]-->
and this:
$user_agent = getenv("HTTP_USER_AGENT");
if (preg_match("MSIE 6", $user_agent))
{
include("fconditionals.php");
}
The first version would never work. PHP only cares about <?php ?> pairs and utterly ignores anything outside of them. The IE conditional comments are only used by the browser, so the include would get executed on the server every time.
The second version has the logic reversed - you're including the file anytime IE6 is detected. you'd want !preg_match instead. However, remember that the user agent string is under user control and can be faked/hacked/subverted. There's no 100% reliable method of detecting the remote browser that can't be subverted somehow.
The first thing you tried (Conditional Comments) won't work because the include is done on the server, while the page is being generated, and the conditional comments are only checked by the browser after the page has been downloaded.
The conditional comments will exclude the generated code from being displayed in IE6, but it will still be run by the server.
Additionally, the conditional comments in the format you've used them here will also exclude the code from being displayed by all non-IE browsers. If you only want to affect IE, you need to re-format it so that the other browsers don't treat the code inside as a comment, by using the <![if !IE 6]> syntax instead of <!--[if !IE 6]>.
That method still won't stop the code from being run on the server though.
The second method you tried is more likely to be closer to what you actually want to do. However, please note that although PHP does receive the USER_AGENT string, it is possible in most browsers to spoof the USER_AGENT, and some privacy/security products actively remove it, as do some web proxies. In other words, the USER_AGENT string is not a 100% reliable way of determining what browser someone is using.
That said, if you have specific PHP code that you want to exlude from being executed only for IE6, then it may be the only viable solution.
The reason this didn't work for you is that your code includes only IE6 rather than excluding it. You need to add a 'not' operator (!) in front of the preg_match().
By the way: In your example code, you have $user_agent = getenv("HTTP_USER_AGENT");. It's worth pointing out that $_SERVER['USER_AGENT'] is already available as a variable, you don't need to use getenv().
if (!strstr($_SERVER['HTTP_USER_AGENT'],"MSIE 6")
{
include("fconditionals.php");
}
I want to send some info back to my database when a user prints a certain web page. I can do this in IE with onbeforeprint() and onafterprint() but I would like to browser agnostic way of doing the same thing. Don't care which combination of technologies I have to use (PHP, MySQL, JavaScript, HTML) so long as it gets done. Any ideas?
EDIT:
Still having some problems with this. I tried the putting my function in my Print.css as an image, but I am messing it up some how. Then I tried just adding a event listener, but I cannot get that to work quite right either. If anyone can provide some more details on how I might call a function right before print in ANY browser I would appreciate it.
EDIT:
I am giving up on this for now, I have settled with another way of doing what I want. I look forward to the day when FireFox supports onbeforeprint() and onafterprint().
Many browsers now support window.matchMedia. This API allows you to detect when CSS media queries go into effect (e.g., rotating the screen or printing the document). For a cross-browser approach, combine window.matchMedia with window.onbeforeprint/window.onafterprint.
The following may result in multiple calls to beforePrint() and afterPrint() (for example, Chrome fires the listener every time the print preview is regenerated). This may or may not be desirable depending on the particular processing you're doing in response to the print.
if ('matchMedia' in window) {
// Chrome, Firefox, and IE 10 support mediaMatch listeners
window.matchMedia('print').addListener(function(media) {
if (media.matches) {
beforePrint();
} else {
// Fires immediately, so wait for the first mouse movement
$(document).one('mouseover', afterPrint);
}
});
} else {
// IE and Firefox fire before/after events
$(window).on('beforeprint', beforePrint);
$(window).on('afterprint', afterPrint);
}
More: http://tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/
I m not sure other browsers will allow you to. You could of course specify an image somewhere in a print stylesheet, which probably only will be called on a print, for the onbeforeprint
Try masking the native window.print() with your own...
// hide our vars from the global scope
(function(){
// make a copy of the native window.print
var _print = this.print;
// create a new window.print
this.print = function () {
// if `onbeforeprint` exists, call it.
if (this.onbeforeprint) onbeforeprint(this);
// call the original `window.print`.
_print();
// if `onafterprint` exists, call it.
if (this.onafterprint) onafterprint(this);
}
}())
Updated: comments.
I think that it's simply not possible to this properly. Or at least - not with any technology I know nor with any of the answers given previously.
Both using onafterprint and using serverside dynamic-image-generating script would tell you that the page was printed even when the visitor merely went to print preview mode and then canceled out.
However, I would like to learn how to get the proper information, so that I can be sure that page was actually printed.
Using an adapted version of jquery.inplace.js for some page creation and use an OBDC connection in the background php file to query for content. Everything works, BUT...
I am surprised that IE6, 7, or 8 are all pretty quick, as is chrome, but firefox seems to take quite a few seconds for exactly the same task, in this case.
This is without firebug, or lots of other add-ons enabled. I am puzzled by what to look for.
It is a fairly simple return of some html content.
What would you try?
A cursory look at the source in the SVN doesn't show anything which I believe firefox would have problems with.
Can you explain exactly what is "slow"? Is it the POST request? Have you tried logging the HTTP Headers sent to the server from both IE and FF?
If it's the javascript itself, try running the profiler in firebug; FF might find a specific function a little "heavy" (for instance, one of the regexes).
Also, FF3.5+ already has String.trim*() methods built-in. The code you're using overwrites those with a custom version, which will be much slower and might even be causing firefox to behave oddly. Try changing the source to the following:
if( String.prototype.trim === undefined ) {
String.prototype.trim = function() {
return this.replace(/^\s+/, '').replace(/\s+$/, '');
};
}
That way the plugin will only add the trim method for older browsers.
I'm having issues with a application that I am writing that uses Dojo and Zend Framework. The issue only effects Internet Explorer 6, other versions of IE, ff, chrome and safari work fine with no issues.
When IE6 lands on the login page it crashes with the send details to microsoft dialog box. The login script uses dojo to provide some validation for the users to ensure that their passwords are formatted correctly etc.
I've seen on some forums that addOnLoad() function call in dojo could be the cause and a window.setTimeout() would help. http://www.dojotoolkit.org/forum/dojo-core-dojo-0-9/dojo-core-support/dom-manipulation-addonload-crashes-ie6
The problem I have is how to manipulate the dojo header that we have in the layout.phtml in the application. We currently have in the file this code in the header.
<?php
$this->dojo()->setLocalPath($this->baseUrl().'/javascript/dojo/dojo.js');
$this->dojo()->addStylesheetModule('dijit.themes.tundra');
echo $this->dojo();
?>
This produces the following in the html.
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dijit.form.Button");
dojo.require("dojo.parser");
dojo.addOnLoad(function() {
dojo.forEach(zendDijits, function(info) {
var n = dojo.byId(info.id);
if (null != n) {
dojo.attr(n, dojo.mixin({ id: info.id }, info.params));
}
});
dojo.parser.parse();
});
var zendDijits = [{"id":"username","params":{"regExp":"[a-z0-9_\\+-]+(\\.[a-z0-9_\\+-]+)*#[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2,4})$","invalidMessage":"Please enter a valid email address","trim":"true","required":"true","dojoType":"dijit.form.ValidationTextBox"}},{"id":"password1","params":{"trim":"true","lowercase":"true","regExp":"^.*(?=.{6,})(?=.*\\d)(?=.*[a-zA-Z]).*$","invalidMessage":"Invalid Password. Password must be at least 6 alphanumeric characters","required":"true","dojoType":"dijit.form.ValidationTextBox"}},{"id":"submit","params":{"label":"Login","dojoType":"dijit.form.Button"}}];
How can I change this to try and add the fixes mentioned in the link, or is there another way to write this without IE6 crashing all the time?? I would prefer to fix this than remove all the client validation, just in case the client is using IE6.
thanks...
Can you reduce it down until you find what is crashing IE6? Save off your output as static html, confirm it still crashes IE and start removing code. Take that addOnLoad out altogether - does it still crash? if not, take out the forEach, and so on. Start removing elements from zendDijits array - is there one in particular that causes the trouble?
Is this a stock IE6? Any plugins/addons?
Your php there should be producing a script element to pull dojo.js. You've got soemthing wierd going on - that Zend code is known to work so we need all the information if you want to solve this.