Log in

View Full Version : parse error



gg3558
05-04-2007, 08:23 PM
I am very new to PHP. I am working on a tutorial and know I am typing the code exactly. Even so I get this parse error:
Parse error: parse error, unexpected '!' in C:\FoxServ\www\internetexplorer.php on line 2
Here is the code and any help is greatly appreciated :)
<?php
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') ! = = FALSE) {
echo 'You are using Internet Explorer.<br />';
}
?>

boxxertrumps
05-04-2007, 08:51 PM
there should be no spaces in between the equal signs and the exclamation point.

gg3558
05-04-2007, 09:06 PM
Thank you very much Ryan. You are absolutely correct. It's difficult to tell when spaces are used and when they are not. I really appreciate your help :)

Twey
05-04-2007, 09:13 PM
So, you detect the one browser still in common use that can't handle XHTML, then serve XHTML to it? Smart :p

This is a terrible way to detect IE, since all sorts of browsers can have MSIE in the user agent string for various reasons (hey, to this day IE still tries to pass itself off as being Mozilla 4).

boxxertrumps
05-04-2007, 09:37 PM
I think iv'e covered at least 99% of situations where a browser could be miscontrued as IE through the http user agent...
http://boxxertrumps.bo.funpic.org/h.phps
opera has "Opera" appended to the user agent string while saying its IE, and i remember twey telling me that some browsers have "like MSIE" in the http user agent string.
but that statement should cover all of your bases.

Twey
05-04-2007, 09:56 PM
Only as it currently stands that we know of, though: there's no guarantee that there isn't or won't be some browser out there that will fool your script. If you want to show something to IE only, use conditional comments (http://msdn.microsoft.com/workshop/author/dhtml/overview/ccomment_ovw.asp).

boxxertrumps
05-04-2007, 10:13 PM
I had forgotten about those.
Would I be able to use that in my case? i would have to send a blank content type to override the default one, define the stuff in meta tags and im not sure what behavior would ensue...
also, i didn't think conditional comments were useable in any other browser...

Twey
05-04-2007, 10:31 PM
You can't define a blank content-type through any means. It's against the standard. No, it can't be used to change the content type, since that's outside the HTML. There is currently no effective way to send the text/html content type to IE only. You can do the <meta> tags, but remember that they shouldn't be vital to your page's working: <meta> elements are by nature optional, and should be able to be ignored at the browser's discretion.
also, i didn't think conditional comments were useable in any other browser...Depends what you mean by "useable." Other browsers don't recognise them as anything special, no, but the point of them is that there's no need to.

mwinter
05-05-2007, 09:51 PM
I think iv'e covered at least 99&#37; of situations where a browser could be miscontrued as IE through the http user agent...
http://boxxertrumps.bo.funpic.org/h.phps

It's certainly impossible to always distinguish a spoofed browser from the real thing, but that's why browser detection is a bad idea and should be avoided. Especially server-side.

Regardless, serving XHTML to everything other than IE is ridiculous. Who said that IE is the only user agent that doesn't support XHTML? If you must serve XHTML, use content type-oriented content negotiation. That is the only sensible way to do it. However, why not opt for the far more reasonable choice: forgo XHTML completely - unless a task is impossible without it.

Mike

Twey
05-05-2007, 10:09 PM
If you must serve XHTML, use content negotiation.Except that IE sends Accept: */*, so by the laws of content negotiation one should send it XHTML.

mwinter
05-06-2007, 06:37 PM
Except that IE sends Accept: */*,

When reloading a resource, yes. With basic requests the value is longer, though equally ill-conceived. The former is behaviour that Microsoft should fix as soon as possible. The latter should be changed before Microsoft supports XHTML properly. Microsoft should also add image/png to the Accept header value now that it has adequate support for PNG images.



so by the laws of content negotiation

There are no requirements regarding content negotiation, only recommendations (which are violated, in another way, by Ryan's code). Even so, those recommendations don't lead to your conclusion:



one should send it XHTML.

If a media range matches two or more available variants, the server is free to send any of them. Typically, it is the variant preferred by the author, but that is a subjective choice.

The technique for dealing with IE, and any user agent with similar behaviour, is simple: only serve XHTML if the media type is matched exactly. The code attached and posted below demonstrates this approach. Please excuse the mismatch in filenames; the board won't allow the upload of .php files.

Mike




<?php
require_once('media-range.php');
require_once('media-type.php');

header('Content-Type: text/plain');

echo "{$_SERVER['HTTP_ACCEPT']}\r\n";

$acceptableRanges = getAcceptableMediaRanges();
$availableVariants = array(MediaType::createInstance('application/xhtml+xml'),
MediaType::createInstance('text/html'));

$variant = findBestVariant($acceptableRanges, $availableVariants);
echo 'Normal negotiation: ', is_null($variant) ? 'No acceptable variants!' : $variant, "\r\n";

$variant = findBestMarkupVariant($acceptableRanges, $availableVariants);
echo 'Modified negotiation: ', is_null($variant) ? 'No acceptable variants!' : $variant, "\r\n";



/* Returns the best variant, as a MediaType object, accepted by the client based on media type. If
* no variants are acceptable, null is returned.
*
* $acceptableMediaRanges: an array of MediaRange objects that the client finds acceptable. This
* array must be sorted in ascending order of precedence.
* $availableVariants: an array of MediaType objects that represent the variants that can be sent
* from the server to the client.
*/
function findBestVariant(array $acceptableMediaRanges, array $availableVariants) {
$bestVariant = null;
$bestScore = 0.0;

foreach ($availableVariants as $variant) {
$i = count($acceptableMediaRanges);
while ($i--) {
$mediaRange = $acceptableMediaRanges[$i];
if ($mediaRange->match($variant) && ($mediaRange->getQuality() > $bestScore)) {
$bestVariant = $variant;
$bestScore = $mediaRange->getQuality();
}
}
}
return $bestVariant;
}

/* Returns the best markup variant, as a MediaType object, accepted by the client based on media
* type. The function considers the relative lack of support for XHTML, only returning such a
* variant if the user agent accepts it specifically using a concrete media type. If no variants
* are acceptable, null is returned.
*
* $acceptableMediaRanges: an array of MediaRange objects that the client finds acceptable. This
* array must be sorted in ascending order of precedence.
* $availableVariants: an array of MediaType objects that represent the variants that can be sent
* from the server to the client.
*/
function findBestMarkupVariant(array $acceptableMediaRanges, array $availableVariants) {
$bestVariant = null;
$bestScore = 0.0;

foreach ($availableVariants as $variant) {
$i = count($acceptableMediaRanges);
while ($i--) {
$mediaRange = $acceptableMediaRanges[$i];
if ($mediaRange->match($variant) && ($mediaRange->getQuality() > $bestScore)
&& (($variant->getType() != 'application')
|| ($variant->getSubtype() != 'xhtml+xml')
|| !$mediaRange->isSubtypeRange())) {
$bestVariant = $variant;
$bestScore = $mediaRange->getQuality();
}
}
}
return $bestVariant;
}

/* Returns an array of MediaRange objects that represents the media types accepted by the client.
* The array is sorted by ascending precedence.
*/
function getAcceptableMediaRanges() {
if (isset($_SERVER['HTTP_ACCEPT'])) {
if (!preg_match_all('<\s*((?:[^,"]|"(?:\\\\.|[^"])*")+)\s*(?:,|$)>',
$_SERVER['HTTP_ACCEPT'], $listItems, PREG_SET_ORDER))
sendBadRequest();
try {
foreach ($listItems as $item)
$ranges[] = MediaRange::createInstance($item[1]);
} catch (InvalidArgumentException $iae) {
sendBadRequest();
}
usort($ranges, array('MediaRange', 'compare'));
}
/* If no Accept header is sent by the user agent, all media types are assumed to be acceptable.
* 14.1 Accept, RFC 2616.
*/
else $ranges[] = new MediaRange('*', '*');
return $ranges;
}

function sendBadRequest() {
header('HTTP/1.1 Bad Request', 400);
exit();
}
?>

boxxertrumps
05-06-2007, 06:53 PM
That'll help tons, i had never considered content negotiation (never knew it existed...) but now that i know i'll be able improve my coding further.
Thanks Mwinter, Twey, Your insights are always helpfull in creating a better internet.

mwinter
05-06-2007, 07:38 PM
That'll help tons, i had never considered content negotiation (never knew it existed...)

You were using it already: the User-Agent header is a possible dimension (all request headers are, actually), but it's not one I would advise using. Like using feature detection in client-side scripting, the Accept header indicates what the user agent is capable of processing - at least in principle.

One thing that I didn't get to demonstrate in the code below is the necessity of the Vary header. When negotiating a response, the Vary response header should contain a list of request headers that determined the variant returned to the client. If the Vary header isn't sent, a cache might retrieve an XHTML response for one client and send it later to another which needed a HTML document.

Section 12 of RFC 2616 (ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt) [ftp] describes content negotiation in more detail, as does various parts of sections 3 and 14.

Mike