Having fun with Opera and PHP

Potassium, a friend of mine, asked me to take a look at his PHP-script (shudder), which was – surprise, surprise – not working. What I did not anticipated were the hours of „fun” that followed.

 


 

This was our starting-point, an innocent looking PHP-script:

if($do == "edit_profile"){
    $Type = !empty($_GET["Type"]) ? $_GET["Type"] : "";
    if(!empty($Type)){
        $Text = $_POST["Text"];
        $sql = "UPDATE ".TABLE_PROFILES." SET Profile_Text = '".$Text."' WHERE Profile_Type = '".$Type."' AND User_ID = '".$_SESSION['UID']."' LIMIT 1";
        echo $sql;
        $query = mysql_query($sql);#,__FILE__,__LINE__);
        echo mysql_error();
        $Body = "Das Profil wurde erfolgreich aktualisiert.<br>Klicken Sie <a href=''>hier</a> um das geänderte Profil anzusehen.<br><a href=''>Zurück zur Profilverwaltung</a><br><br>";
    }
}
As you can see, nothing unusual. There is the usual missing error-handling you can expect in PHP scripts and the values, that come from the browser are not validated in any way (hello SQL-Injection). But the problem was, that the value for $Text was not added to the database. If you executed the SQL-Statement on the SQL command line, it ran perfectly. So we tried to debug the problem, entering echo-statements, adding error-handling and the like. We changed the column from „text” to „varchar” and die names of the html form fields in the hope to find the problem – nothing. Several hours later, I got a look at the html form, potassium was working with. It looked like this:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML>
    <HEAD>
        <TITLE>POST Test</TITLE>
    </HEAD>
    <BODY>
        <h1>POST Test</h1>
        <form name="demoform1" method="post" action="http://www.example.com/cgi-bin/printenv?do=edit_profile&Type=Test" >
            <input type="text" name="KOVO" value="47110915" size="80"><br/><br/>
            <input type="reset" value="Zurücksetzen"> <input type="submit" name="Speichern">
        </form>
    </BODY>
</HTML>
Now this rang some alarm-bells. What I learnd in the last 11 years making website was, that you should not mix URL-parameters and form fields. Either, you put everyting in the URL, or you add hidden fields but you don’t mix the two. So I told Potassium to convert the two URL-parameters „do” and „Type” into hidden fields and try again. Badabim, badabum and it worked. :) We investigated further and found out, that the Opera browser Potassium used, was part of the problem. Firefox and IE caused no problems using the mixture of URL-parameters and form fields, but Opera did. I investigated further and found a possible explanation. Potassium used POST to send the data to the server, which is OK, as you should use POST if you plan to change data on the server. Yeah, RFC nuts like me know this stuff by heart. But you should also take the If you also take the CGI specification into account. Regarding POST actions it says:
For requests which have information attached after the header, such as HTTP POST or PUT, the information will be sent to the script on stdin.
 
The server will send CONTENT_LENGTH bytes on this file descriptor.
So if you POST someting to the Server, even if it is running PHP, Perl, etc., the data still has to be read from STDIN. So the PHP runtime on Potassiums server reads the data from STDIN. In order to stop reading after the last byte of information it checks CONTENT_LENGTH for the length of the data. If the query looked like „a=b&b=c”, CONTENT_LENGTH would contain the value 7. After this brief excursion into the world of HTML, HTTP and CGI Standards, let’s go back to our problem at hand: why the form working in Firefox and IE, but not in Opera. I wrote myself a litte testscript a long while ago, that just dumps all the CGI information to the browser, whatever the request looks like. Now, if I sent the form data to this little script using Firefox, I got an CONTENT_LENGTH="44" back. Doing the same thing in Opera, it said CONTENT_LENGTH="30" and with IE it was CONTENT_LENGTH="30". WTF?!?! How can that be? At first, there was no clue for me as to why those f*’$§! browsers sent different content lengths. It was time for desperate measures. I started up fiddler to check what the browsers were actually sending. The data my little script displayed in the browser is only the interpreted values, I wanted to see the raw data. And thats what I got (excerpts):
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Content-Length: 38
KOVO=47110915&Speichern=Anfrage+senden
 
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6
Content-Length: 42
KOVO=47110915&Speichern=Anfrage+abschicken
 
User-Agent: Opera/9.01 (Windows NT 5.1; U; en)
Content-Length: 30
KOVO=47110915&Speichern=Submit
I can see clearly now. ROTFL. As Potassium didn’t asign a value to the submit button, every browser added his default text. So you get „Anfrage+senden” from IE, „Anfrage+abschicken” from Firefox and a short „Submit” from Opera. That’s why there were different values for the Content-Length, as they are calculated from the fieldnames and the values of the fields. ARGL. OK, now keep in mind, that on the server side, the application is only allowed to read data as far as CONTENT_LENGTH says. And the data, in our case, consists of the form-values AND the URL-parameters. So, armed with all this knowledge, let’s take a look at the work of the PHP server. For this demonstration, I concated all the data and added a „line” for the content length: IE:
         1         2         3        
12345678901234567890123456789012345678
do=edit_profile&Type=Test&KOVO=47110915&Speichern=Anfrage+senden
No problems here, PHP stops reading the data after the needed value, so we have the data (the actual data was shorter, so just ignore the missing „5” ;) ). Firefox:
         1         2         3         4
123456789012345678901234567890123456789012
do=edit_profile&Type=Test&KOVO=47110915&Speichern=Anfrage+abschicken
Same here, 42 characters is just enough for KOVO to come through. And Opera:
         1         2         3         4
123456789012345678901234567890
do=edit_profile&Type=Test&KOVO=47110915&Speichern=Submit
Voila. KOVO was never seen properly in PHP. So, what lessons can be learned from this? If you are using POST, DO NOT use URL-Parameters. Put them into hidden fields where they belong. Otherwise, you run into problems.

Tagged as: , , , , , | Author:
[Freitag, 20060915, 19:02 | permanent link | 0 Kommentar(e)

Comments are closed for this story.


Disclaimer

„Leyrers Online Pamphlet“ ist die persönliche Website von mir, Martin Leyrer. Die hier veröffentlichten Beiträge spiegeln meine Ideen, Interessen, meinen Humor und fallweise auch mein Leben wider.
The postings on this site are my own and do not represent the positions, strategies or opinions of any former, current or future employer of mine.

Search

RSS Feed RSS Feed

Tag Cloud

2007, a-trust, a.trust, a1, accessability, acta, advent, age, amazon, ankündigung, apache, apple, audio, austria, backup, barcamp, bba, big brother awards, birthday, blog, blogging, book, books, browser, Browser_-_Firefox, buch, bürgerkarte, cars, cartoon, ccc, cfp, christmas, cloud, collection, computer, computing, concert, conference, copyright, database, date, datenschutz, debian, delicious, demokratie, design, desktop, deutsch, deutschland, dev, developer, digitalks, dilbert, disobay, dna, dns, Doctor Who, documentation, Domino, domino, Douglas Adams, download, drm, dsk, dvd, e-card, e-government, e-mail, e-voting, E71, Ein_Tag_im_Leben, email, eu, event, exchange, Extensions, fail, feedback, film, firefox, flightexpress, food, foto, fsfe, fun, future, games, gaming, geek, geld, gleichberechtigung, google, graz, grüne, grüninnen, hack, hacker, handtuch, handy, hardware, HHGTTG, history, how-to, howto, hp, html, humor, IBM, ibm, ical, image, innovation, intel, internet, internet explorer, iphone, ipod, isp, it, IT, java, javascript, job, journalismus, keyboard, knowledge, konzert, language, laptop, law, lego, lenovo, life, links, Linux, linux, linuxwochen, linuxwochenende, living, lol, london, lost+found, Lotus, lotus, Lotus Notes, lotus notes, LotusNotes, lotusnotes, lotusphere, Lotusphere, Lotusphere2006, lotusphere2007, Lotusphere2008, lotusphere2008, lustig, m3_bei_der_Arbeit, mac, mail, marketing, mathematik, media, medien, metalab, Microsoft, microsoft, mITtendrin, mobile, mood, movie, mp3, multimedia, music, musik, männer, nasa, netwatcher, network, netzpolitik, news, nokia, notes, Notes, Notes+Domino, office, online, OOXML, open source, openoffice, opensource, orf, orlando, os, outlook, patents, pc, pdf, perl, personal, php, picture, pictures, podcast, politics, politik, pr, press, presse, privacy, privatsphäre, productivity, programming, protest, qtalk, quintessenz, quote, quotes, radio, rant, recherche, recht, release, review, rezension, rss, science, search, security, server, sf, shaarli, Show-n-tell thursday, sicherheit, silverlight, SnTT, social media, software, sony, sound, space, spam, sprache, spö, ssh, ssl, standards, storage, story, stupid, summerspecial, sun, sysadmin, talk, technology, The Hitchhikers Guide to the Galaxy, theme, think, thinkpad, tip, tipp, tools, topgear, torrent, towel, Towel Day, TowelDay, travel, truth, tv, twitter, ubuntu, uk, unix, update, usa, vds, video, videoüberwachung, vienna, vim, Vim, vista, vorratsdatenspeicherung, vortrag, wahl, wcm, web, web 2.0, web2.0, web20, Web20, webdesign, werbung, wien, wiener linien, wikileaks, windows, windows 7, wired, wishlist, wissen, Wissen_ist_Macht, wlan, work, wow, wtf, wunschzettel, Wunschzettel, www, xbox, xml, xp, zensur, zukunft, zune, österreich, övp, übersetzung, überwachung

AFK Readinglist