{"id":83,"date":"2005-04-19T07:37:38","date_gmt":"2005-04-19T13:37:38","guid":{"rendered":"\/?p=83"},"modified":"2005-04-19T07:37:38","modified_gmt":"2005-04-19T13:37:38","slug":"passing-text-between-web-components","status":"publish","type":"post","link":"https:\/\/www.codedread.com\/blog\/archives\/2005\/04\/19\/passing-text-between-web-components\/","title":{"rendered":"Passing Text Between Web Components"},"content":{"rendered":"<p>In designing a little on-line chat program accessible through a web browser, I came across what was one of the most frustrating problems in my software development career.  <!--more--><\/p>\n<div class=\"ads\"><object type=\"text\/html\" width=\"468\" height=\"60\" data=\"http:\/\/www.codedread.com\/gads.php\"><\/object><\/div>\n<p>Here's what I wanted to do:<\/p>\n<p>1) User types in some text on a form and submits the form<br \/>\n2) JavaScript mangles the text so that it is not easily readable and sends the disguised text to a server-side script<br \/>\n3) Server-side script writes any text received to the end of a \"conversation\" file as XML<br \/>\n4) Server-side script mangles the XML document and sends back to all attached clients<br \/>\n5) Client receives the mangled text, un-mangles and generates an XML document, extracts the text, and displays on the screen<\/p>\n<p>The overall process is pretty simple and is represented by the following diagram:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/www.codedread.com\/images\/chat_flow.jpg\" alt=\"flow of text throughout the chat application\"><\/img><\/p>\n<p>The frustrating part came when I started encountering the quirks of the various languages\/syntaxes that I was using coupled with the requirement to be able to pass <em>any<\/em> text to the server.  Things got confusing fast, and as they always say, the devil is in the details.<\/p>\n<h2>Sending Text from JavaScript to PHP<\/h2>\n<p>The transition from user text to mangled text is a simple function (written in both JavaScript and PHP) that takes an input string of N characters and returns an output string of N characters.  The function works transitively (such that mangled text becomes un-mangled and vice versa) for convenience.  This is the really simple part of the process:<\/p>\n<div class=\"code\">\nvar outStr = mangle(\"Our sample text\");<br \/>\n\/\/ outStr is now \"ubW(&2v A;(z;+z\"\n<\/div>\n<p>However, it is when we want to actually send this output string as a URL argument to a server-side PHP script that we encounter our first problem.  For example:<\/p>\n<div class=\"code\">http:\/\/www.mydomain.com\/chat.php?USER=Jeff&TEXT=....<\/div>\n<p>Just as with text entered from the form, the mangled string could contain <em>any<\/em> printable ASCII character.  But the ampersand character (\"&#38;\") is used to delimit URL variables in PHP and valid URLs cannot have spaces (\" \") in them.  There are other characters that have special meaning in URLs as well.  Thus, if we tried to put our outStr into the URL it would become:<\/p>\n<div class=\"code\">http:\/\/www.mydomain.com\/chat.php?USER=Jeff&TEXT=ubW(&2v A;(z;+z<\/div>\n<p>The portion after the space (i.e. \"<span style=\"color: blue\">A;(z;+z<\/span>\") is removed from the URL.  Also, the $TEXT variable from the PHP side would contain only \"<span style=\"color: blue\">ubW(<\/span>\" and the remaining string is interpreted as another PHP variable called \"<span style=\"color: blue\">2v<\/span>\".<\/p>\n<p>What we want is for the PHP script to see one variable called $TEXT with the complete mangled string.  Thus, it is important that we escape the mangled string such that spaces become \"%20\", ampersands become \"%26\", \"=\" become \"%3D\", and other characters like \"%\" become \"%25\".  i.e. any character that might be interpreted in a special way inside a URL  Thankfully we can just use the JavaScript escape() function for this.  Handy-dandy:<\/p>\n<div class=\"code\">\nvar outStr = mangle(\"Our sample text\");<br \/>\n\/\/ outStr is now \"ubW(&2v A;(z;+z\"<br \/>\noutStr = escape(outStr);<br \/>\n\/\/ outStr is now \"ubW(%26v%20A;(z;+z\"<br \/>\nvar urlStr = \"http:\/\/www.mydomain.com\/chat.php?USER=Jeff&TEXT=\" + escape(outStr);<br \/>\n\/\/ urlStr is now http:\/\/www.mydomain.com\/chat.php?USER=Jeff&TEXT=ubW(%26v%20A;(z;+z\"\n<\/div>\n<p>Now we can send this string to the PHP script, right?  Almost, but not quite!  It seems that the \"+\" character in a URL is automatically translated into a space by PHP.  Thus, if we really want to send the + character in our URL we'll also need to escape it as \"%2B\" (and only AFTER we escape the rest of our string, otherwise its \"%2B\" would become \"%252B\"!!):<\/p>\n<div class=\"code\">\nvar outStr = mangle(\"Our sample text\");<br \/>\n\/\/ outStr is now \"ubW(&2v A;(z;+z\"<br \/>\noutStr = escape(outStr);<br \/>\n\/\/ outStr is now \"ubW(%26v%20A;(z;+z\"<br \/>\n<strong>outStr = outStr.replace(\/(+)\/g, \"%2B\");<\/strong><br \/>\n\/\/ outStr is now \"ubW(%26v%20A;(z;%2Bz\"<br \/>\nvar urlStr = \"http:\/\/www.mydomain.com\/chat.php?USER=Jeff&TEXT=\" + escape(outStr);<br \/>\n\/\/ urlStr is now http:\/\/www.mydomain.com\/chat.php?USER=Jeff&TEXT=ubW(%26v%20A;(z;%2Bz\"\n<\/div>\n<p>Is the string safe for PHP now?  Yes, it would seem so.<\/p>\n<p>[NOTE:  When discussing this topic with <a href=\"http:\/\/rr.latenightpc.com\/wp\/\">a friend<\/a> he told me about the encodeURIComponent() function.  However, I had already gone through the above learning experience and I also noted that encodeURIComponent() is not supported in MacIE or Safari...poor Mac users.]<\/p>\n<p>The nice part is that once passed to PHP, the PHP interpreter automatically un-escapes any %xx characters such they magically return to their equivalent single-character representations again.<\/p>\n<p>But!  Apart from unescaping the %xx characters, PHP can also do some mangling of its own.  This depends on whether or not the \"magic quotes\" feature is enabled or not.  If it is, then PHP automatically adds backslashes to specific characters (single-quote and double-quotes) presupposing that you're going to try and shove the text into a database.  This is NOT what we want, as extra characters changes the content that was originally typed when you un-mangle things.  i.e. we'll have extra characters in our returned string.  You can avoid this on the PHP side by either configuring PHP to not use magic quotes (via php cfg files or .htaccess) or use some simple PHP code:<\/p>\n<div class=\"code\">\nif(get_magic_quotes_gpc()) {<br \/>\n&#160;&#160;$thechatmsg = stripslashes($TEXT);<br \/>\n}<\/div>\n<p>Now $TEXT should contain \"ubW(&2v A;(z;+z\" again.  We're finally back to our mangled version of the text from the JavaScript.<\/p>\n<p>However, the fun doesn't stop there.  In fact, we've only made it from (1) to (2) in our diagram.<\/p>\n<h2>Creating XML in PHP<\/h2>\n<p>Now we need to un-mangle the text and shove it into an XML document:<\/p>\n<div class=\"code\">\nif(get_magic_quotes_gpc()) {<br \/>\n&#160;&#160;$thechatmsg = stripslashes($TEXT);<br \/>\n}<br \/>\n<strong>$thechatmsg = mangle($thechatmsg);<\/strong>\n<\/div>\n<p>There, now we have un-mangled text, but before we can blindly shove it into a XML document, we have to make sure that the original text typed by the user doesn't violate the allowed characters of an XML document (namely &#60; and &#62; characters).  As you may know, XML documents rely heavily on markup tags and thus, characters such as &#60; and &#62; are verbotten within the XML document contents itself.  Since the receiving clients expect a valid XML document we have to take care that any of the data we're shoving into the XML document does not invalidate the syntax required.  PHP provides a simple function for this called htmlspecialchars():<\/p>\n<div class=\"code\">\nif(get_magic_quotes_gpc()) {<br \/>\n&#160;&#160;$thechatmsg = stripslashes($TEXT);<br \/>\n}<br \/>\n$thechatmsg = mangle($thechatmsg);<br \/>\n<strong>$thechatmsg = htmlspecialchars($thechatmsg, ENT_QUOTES);<\/strong>\n<\/div>\n<p>We are finally ready to format $thechatmsg into a XML document and write to a file:<\/p>\n<div class=\"code\">\nif(get_magic_quotes_gpc()) {<br \/>\n&#160;&#160;$thechatmsg = stripslashes($TEXT);<br \/>\n}<br \/>\n$thechatmsg = mangle($thechatmsg);<br \/>\n$thechatmsg = htmlspecialchars($thechatmsg, ENT_QUOTES);<br \/>\n<strong>$xmlStr = sprintf(\"&#60;chat xml:space=\"preserve\"&#62;&#60;msg id=\"%d\"&#62;&#60;user&#62;%s&#60;\/user&#62;&#60;text&#62;%s&#60;\/text&#62;&#60;\/msg&#62;&#60;\/chat&#62;\", $n, $USER, $thechatmsg);<br \/>\nfwrite($f, $xmlStr);<br \/>\n<\/strong>\n<\/div>\n<p>We use xml:space=\"preserve\" to indicate that whitespace within the XML document should be preserved.<\/p>\n<p>Now we've made it safely from (2) to (3).  We've sent the mangled text across the network to a PHP script and the PHP script has un-mangled it, written it into an XML document to the filesystem.  Next, we have to send all new messages back to the JavaScript call in the form of an XML document (as a response to a XMLHttpRequest).<\/p>\n<h2>Sending Text from PHP to JavaScript<\/h2>\n<p>This is actually pretty straightforward PHP code:<\/p>\n<div class=\"code\">\n$xmldoc = \"\";<br \/>\nwhile(!feof($f)) {<br \/>\n&#160;&#160;$line = trim(fgets($f));<br \/>\n&#160;&#160;if(strlen($line) > 0) {<br \/>\n&#160;&#160;&#160;&#160;$xmldoc .= $line;<br \/>\n&#160;&#160;}<br \/>\n} \/\/ while (loop<br \/>\n\/\/ now mangle the entire XML document<br \/>\n$xmldoc = mangle($xmldoc);<br \/>\nprintf(\"%sn\", $xmldoc);\n<\/div>\n<p>Now we've made it from (3) to (4).  The only thing left for the client to do is to un-mangle it, reformat it into an XML document, walk the document nodes and extract the information.<\/p>\n<h2>Creating an XML Document From Text in JavaScript<\/h2>\n<p>Since browsers have different means of doing this, I decided to use <a href=\"http:\/\/sarissa.sourceforge.net\/doc\/\">Sarissa<\/a> which abstracts these differences and lets me just deal with the XML document itself.<\/p>\n<p>The mangled text comes back as the responseText field of the XMLHttpRequest object (not as valid XML).  I take this string, un-mangle it, and create an XML document out of it:<\/p>\n<div class=\"code\">\nvar xmlString = mangle(req.responseText);<br \/>\nvar oDomDoc = Sarissa.getDomDocument();<br \/>\noDomDoc.loadXML(xmlString);<br \/>\n\/\/get the root node<br \/>\nvar xmldoc = oDomDoc.documentElement;\n<\/div>\n<p>The one caveat I had is that regular HTML does not (by default) preserve whitespace.  To get around this, I used the CSS rule \"white-space: pre\".<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In designing a little on-line chat program accessible through a web browser, I came across what was one of the most frustrating problems in my software development career.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[31,38,42,25,11,28,30],"tags":[],"class_list":["post-83","post","type-post","status-publish","format-standard","hentry","category-ajax","category-javascript","category-php","category-software","category-technology","category-web","category-xml"],"_links":{"self":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/83","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/comments?post=83"}],"version-history":[{"count":0,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/83\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/media?parent=83"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/categories?post=83"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/tags?post=83"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}