How to minify "a priori" php files that output javascript? - javascript

We have some PHP files that output JavaScript code. I know things could have been different, but that was a decision taken during the start of the project.
We have several PHP files which generate Javascript files, something like:
<?php Header("content-type: application/x-javascript");
if(strlen($_GET['country']) != 2){ exit;} //avoids code injection
include_once($_SERVER['DOCUMENT_ROOT'].'/countries/'.$_GET['country'].'.php');?>
/*Define GLOBAL Javascript variables*/
var COUNTRY = "<?php echo $GLOBALS["country"]; ?>";
/*Language code according to ISO_639-1 codes*/
var LANGUAGE = "<?php echo $lang_CT[$GLOBALS["country"]]; ?>";
...
What is the best way to minify that code a priori, i.e., not when the file is called or echoed, but on the server, using the Javascript minifying rules?
edit: I've been thinking and things might be complex to achieve, I imagine this case of invalid JS code:
var str = <?php echo "'a string';"; ?>
which outputs a valid JS code
var str = 'a string';
but basically I was wondering if there is any basic minifying option, to remove double spaces, comments and breaklines, which would then not affect the generated JS code.

AFAIK there is no support for achieving this as an integrated feature of PHP as you obviously want to minify code which is actually ignored by PHP due to not residing in process instructions <?php and ?>. So you will need to process your PHP code with another tool. If that is to be written in PHP, too, I might give the following code fragment a try:
$sequence = preg_split( '/(<\?php|<\?=|\?>)/', $phpFileCode, null, PREG_SPLIT_DELIM_CAPTURE );
$isPHP = false;
foreach ( $sequence as &$segment ) {
switch ( $segment ) {
case '<?php' :
case '<?=' :
$isPHP = true;
break;
case '?>' :
$isPHP = false;
break;
default :
if ( !$isPHP ) {
$segment = preg_replace( array(
'#\s*/\*.*?\*/\s*#', // matching multi-line comments
'#\s*//.*$#m', // matching single-line comments
'#\s+#', // matching arbitrary sequences of whitespace incl. multiple blank lines
), array(
' ',
' ',
' ',
) );
}
}
}
$phpCodeMinified = implode( '', $sequence );
Note: This code is just a scribble ... I haven't tested it, but I think it's pointing towards some quite simple approach.
A more elaborate approach might
use this code to replace all PHP process instruction sequences with some special global variable name in Javascript rather than detecting segments not belonging to PHP. E.g. use names like window.__PHPreplacedXXXX where XXXX is the numeric index of an array the whole replaced PHP segment has been pushed to for recovery in step 3 below. By using global names they won't be mangled in next step.
mangle the resulting code using some JS minifier such as uglify or minify referenced before.
process the resulting minified JS file and revert previous replacement of PHP sequences with global names.
This might enable use of more aggressive minification, but might result in broken JS code either when minifier is optimizing and reorganizing code. The risk isn't that high though when sticking with "simple" minifiers.

Here's what I would do; put all the Javascript in a variable using Heredoc, for example:
$js = <<<EOD
console.log('Valar Morgulis');
console.log('Valar Dohaeris');
EOD;
Then use the minify_js() function that can be found here on Github, or something similar. Here's the function:
function minify_js($input) {
if(trim($input) === "") return $input;
return preg_replace(
array(
// Remove comment(s)
'#\s*("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')\s*|\s*\/\*(?!\!|#cc_on)(?>[\s\S]*?\*\/)\s*|\s*(?<![\:\=])\/\/.*(?=[\n\r]|$)|^\s*|\s*$#',
// Remove white-space(s) outside the string and regex
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/)|\/(?!\/)[^\n\r]*?\/(?=[\s.,;]|[gimuy]|$))|\s*([!%&*\(\)\-=+\[\]\{\}|;:,.<>?\/])\s*#s',
// Remove the last semicolon
'#;+\}#',
// Minify object attribute(s) except JSON attribute(s). From `{'foo':'bar'}` to `{foo:'bar'}`
'#([\{,])([\'])(\d+|[a-z_][a-z0-9_]*)\2(?=\:)#i',
// --ibid. From `foo['bar']` to `foo.bar`
'#([a-z0-9_\)\]])\[([\'"])([a-z_][a-z0-9_]*)\2\]#i'
),
array(
'$1',
'$1$2',
'}',
'$1$3',
'$1.$3'
),
$input);
}
minify_js($js); would get you the minified JS. You can use variables inside Heredoc, more information here.

Related

Passing PHP array to Javascript w/o showing up in source

I'm working on a historical database with 2,000+ photos that need to be categorized of which about 250 are loaded. I've created a MYSQL database with 26 fields to hold this data.
I'm using PHP to access the database and retrieve the information.
I'd like to use JavaScript to manage the rest of the form. All of the code is in one php file.
The problem I'm running into is when I
//$result is the php associative array holding the photo information
<div id="dom-target" style="display: none;">
<?php echo json_encode($result); ?>
</div>
<script>
var div =document.getElementById("dom-target");
var photo_array = JSON.parse(div.textContent);
It works but, I get the entire database structure and data embedded in the source html output. Obviously this won't do especially as the photo count increases.
How can I prevent this?
If I were to split this one php file into two, one containing php accessing the database and returning an array, and the other page containing all of the input boxes etc., and use AJAX passing the array as a JSON; would that work? I'd hate to go down that path unless it'll be successful. I've read where you can't pass the array if all of the code is on one page.
Or, should I just stick with doing everything in php?
Thanks, Eric
Edit: What I want to do is to pass a php array to js without having all of the data in the array included in the source. By source I mean when someone "views source". I also think that once I get up to 2,000 photos is is going to be unwieldy....(2,000 photos) x (26 fields) = a lot of stuff needlessly included in the web page.
I have no objection to using AJAX. But all of the examples I've seen have the request on one page and the response on another. Do I need to split up my code onto two pages; one to handle the php and MySQL and the other to handle the html and js?
What I envision is a screen showing the selected photo at 800x600 with the input fields below that. A person enters the title, caption, description etc and that is saved in the db with the photo's name. Below that I would have 20 thumbnail photos which a person could pick from to enter that photo's information. I would loop through the database 20 or so, photos at a time. Only the file names are stored in the database, the actual photo jpg is stored on a hard disk and retrieved via an statement.
How can I do this without all of the data in the database array being on the html source page?
Edit 2: I've been asked to include more of my php. Sorry I couldn't make it neater.
<?php
$stmt_select->bind_result(
$select_array['fhs_pkey'],
$select_array['file_name'],
$select_array['caption'],
$select_array'post'],
$select_array['photo_type'],
$select_array['last_name'],
$select_array['first_name'],
$select_array['middle_name'],
$select_array['honorific'],
etc., etc., etc
);
// put all of the database info into an array. Filename field is for full size photos
$j=$stmt_select->num_rows;
for ($i=0;$i<$j;$i++)
{
$stmt_select->data_seek($i);
$row = $stmt_select->fetch();
//put all of the column data into the array
foreach ($select_array as $key=>$value)
$result[$i][$key]=$value;
//in a separate php file resize the photos and save them
//put full path with appended filename to retrieve later
$result[$i]['resized'] =
"../images/fhs_images/800x600_photos/800x600--" .
$result[$i]['file_name'] ;
$result[$i]['thumb'] = "../images/fhs_images/200x150_photos/200x150--" .
$result[$i]['file_name'] ;
}
$stmt_select->close();
$stmt_update->close();
$stmt = null;
$conn = null;
echo '<figure id="photo_figure">';
$filename = $result[2]['resized'];
echo "<img src = "."'".$filename."'" ."/>";
?>
<script>
//below is where I get the entire array printed out when I view source
var photo_array = <?php echo json_encode($result); ?>
var testing = photo_array[40]['thumb'];
//take care of spaces in filenames
testing = encodeURI(testing)
document.write('<img src=' + testing + '>')
</script>
Edit 3 #trincot
Something's not right. I moved all of my MYSQL db setup and retrieve into a new file called fhs_get_photos.php. In my jQuery ready function I added the below. See my comments on what gets displayed
var myarray;
$(document).ready(function()
{
$('.tooltips').powerTip();
$(".radio1").on('click',(function()
{
var photo_type = $("input[name='photo_type']:radio:checked").val();
if(photo_type == 2)
$(".person").hide();
else
$(".person").show();
}));
$.getJSON("fhs_get_photos.php", function(photo_array)
{
if (photo_array.jsonError !== undefined)
{
alert('An error occurred: ' + photo_array.error);
return;
}
// photo_array now contains your array.
// No need to decode, jQuery has already done it for you.
// Process it (just an example)
//$.each(photo_array, function(i, obj){
// $("#dom-target").append(obj.fhs_pkey + " " + obj.file_name + ", ");
//this displays correctly on a screen but not with anything else.
//Seems as if it's rewriting the page and only this is displaying which
//may be how it's supposed to go
document.write("In js. photo_array 2,caption is: " + photo_array[2] ['caption']);
});
});
In my main php I put
document.write("photo_array 2,caption is: " + photo_array[2]['caption']);
but it's not displaying anything. I suspect photo_array is not being passed into the page. In the js file, I then created a global variable 'myarray' and in the .getJason function I added
myarray = photo_array;
thinking it would pass into the main file but it didn't.
There are in principle two ways you can think of to get data in JavaScript:
1. Ajax request
With this solution use your current PHP file for generating the HTML page only, so without generating JSON, and create another PHP file which will generate the JSON only.
So let's say your JSON-generating PHP file is called fhs_get_photos.php, then it would have this code (no HTML!):
<?php
header("Content-Type: application/json");
// Collect what you need in the $result variable.
// ...
// and then:
echo json_encode($result);
?>
See the last section in my answer for treating JSON encoding errors.
Make sure there are no line breaks or spaces before the opening <?php, and that you do not echo or print anything else than that one JSON string.
Your database query would also be in this new file. Note that currently you have a mix, like with this line:
echo "<img src = "."'".$filename."'" ."/>";
This line belongs in the non-JSON file, but it also depends on the query. So either you make an include file that does the query, include it in both PHP files, or you move the logic of defining the image tag (or at least the image's source) to the JavaScript part (better!).
Then in the original PHP file, remove the JSON output, and add some JavaScript, using jQuery (I understood you were already using it, so you have it included):
$(function(){
$.getJSON("fhs_get_photos.php", function(photo_array){
// photo_array now contains your array.
// No need to decode, jQuery has already done it for you.
// Process it (just an example)
$.each(photo_array, function(i, obj){
$("#dom-target").append(obj['fhs_pkey'] + " " + obj['file_name'] + ", ");
});
// or things like:
$("#caption_input").val(photo_array[2]['caption']);
});
});
This function will get executed once the HTML DOM has been built, so evidently after the first PHP file has finished execution. It will make the request to the second PHP file. Once that request is answered by PHP, the inner call-back function will receive the data. Note that there is no need to decode JSON here, as jQuery has already done that for you.
2. Generate JavaScript with data
Here you keep your current PHP file, but move the part where you inject the JSON encoded data to the JavaScript block:
<script>
var photo_array = <?php echo json_encode($result); ?>;
// ... process it
</script>
There is no need to wrap JSON in a JavaScript string to then parse it.
From json.org:
JSON is a subset of the object literal notation of JavaScript. Since JSON is a subset of JavaScript, it can be used in the language with no muss or fuss.
2.1. Valid JSON that could be invalid JavaScript?
Although not a problem in the context of this question (see below), there is an incompatibility between JSON and JavaScript syntax. It concerns whether or not the non-ASCII characters U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are allowed to appear unescaped in quoted strings:
JSON syntax allows this, as stated in the ECMAScript® 2015 Language Specification, section 24.3.1:
JSON allows Unicode code points U+2028 and U+2029 to directly appear in String literals without using an escape sequence.
JavaScript syntax does not allow this, as indicated in the ECMAScript® 2015 Language Specification, section 11.8.4:
All code points may appear literally in a string literal except for the closing quote code points, U+005C (REVERSE SOLIDUS), U+000D (CARRIAGE RETURN), U+2028 (LINE SEPARATOR), U+2029 (PARAGRAPH SEPARATOR), and U+000A (LINE FEED). Any code points may appear in the form of an escape sequence.
PHP's json_encode however, follows the possibility offered in that last line, and escapes all non-ASCII characters, including the problematic U+2028 and U+2028, except if you explicitly tell PHP not to do so with the JSON_UNESCAPED_UNICODE flag:
JSON_UNESCAPED_UNICODE (integer)
Encode multibyte Unicode characters literally (default is to escape as \uXXXX). Available since PHP 5.4.0.
So, a json_encode call without this flag will not produce instances of this problem.
3. Catch json_encode failures
According to the manual on json_encode the method can return a non-string (false):
Returns a JSON encoded string on success or FALSE on failure.
When this happens echo json_encode($result) will output the empty string, which is invalid JSON.
This error condition should be captured in PHP, for example like this:
<?php
header("Content-Type: application/json");
// Collect what you need in the $result variable.
// ...
// and then:
$json = json_encode($result);
if ($json === false) {
$json = json_encode(array("jsonError", json_last_error_msg()));
if ($json === false) {
// This should not happen, but we go all the way now:
$json = '{"jsonError": "unknown"}';
}
}
?>
And then in JavaScript, this condition should be handled as well, for example like this:
if (photo_array.jsonError !== undefined) {
alert('An error occurred: ' + photo_array.jsonError);
return;
}

Security of adding php information into javascript

The script I have works perfectly fine but I have done some reading and now I am wondering if this code is secure and if not what would be the secure & correct way of implementing it:
<?php
function get_current_page_url()
{
$url = $_SERVER['REQUEST_URI'];
$main_url = explode('?', $url);
$main_url = explode('/', $main_url[0]);
return $main_url = end($main_url);
}
?>
<script type="text/javascript">
var pageUrl = "<?php echo get_current_page_url() ?>?" + form_data;
</script>
Can you write an answer to this question with the secure & correct way to implement it, preventing these security issues?
Injecting content from PHP into a JavaScript literal in a <script> block:
var current = <?php echo json_encode(get_current_page_url(), JSON_HEX_TAG); ?>;
var pageUrl = current + '?' + form_data;
JSON-encoding produces a string literal including the quotes. This is good enough for JavaScript because JSON literals are (nearly) a subset of JavaScript literals.
(The ‘nearly’ is because due to an oversight in design, raw characters U+2018 and U+2019 are allowable in JSON string literals but not JavaScript. This doesn't matter here as PHP encodes those and other non-ASCII characters to \u escapes anyway.)
The JavaScript is enclosed in a <script> block in an HTML document, so it's essential that if the string </script> is inside the PHP string it doesn't come out directly in the source—if it did it would end not just the string literal, but the whole script block. JSON_HEX_TAG prevents this happening by replacing the < with the escape \u003C. It is not wholly necessary from PHP 5.4 onwards as these versions also escape the / by default.
Using JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS will encode more characters that are special in an HTML context, which isn't wholly necessary here but would allow you to inject into a string in an HTML <script> block as well as an XHTML <script> block or and HTML onxxx="..." event handler without having to perform the extra layer of htmlspecialchars() that could be necessary in these places.
Having said that, you are better off not injecting into JavaScript at all, because keeping track of multiple nested injection contexts is hard. It's better to keep JS out of your HTML documents entirely, ideally. You can inject the content into data- attributes with plain old HTML-escaping, like you should be using everywhere you put content into HTML, and then read the strings direct from the DOM:
<body data-current-url="<?php echo htmlspecialchars(get_current_page_url()); ?>">
...
var current = document.body.getAttribute('data-current-url');
var pageUrl = current + '?' + form_data;
Having said that, all of this is likely superfluous in this case because you can already read the document's URL directly from JavaScript using the location object. Unless you are doing something wacky involving mod_rewrite, it would be the same to say just:
var pageUrl = location.pathname.split('/').pop() + '?' + form_data;
and if all you want is to be able to make a relative link to the current page with a different query string, you don't even need to do that, you can simply use '?' + form_data.

assigning php return value to a javascript variable

I have a database form on a MySql table on which I have a javascript function to populate the options of a select tag. Those options are fetched from a table of clients who have a status of either "Active" or "Inactive", and the return values are of those clients where their status is active. In the event an order is loaded where the client status is inactive, I'm trying to add a handler for inactive clients. The form loads from a php script that left joins the client table to the main table, where clientId in the main table is equal to Id in the client table. So, I have the name and id of the client fetched outside of the function to populate the options list, regardless of their status.
There is one line that is causing me fits. I have searched this site and others and have found many solutions, but none have worked for me so far. This is the line:
var txt = <?php echo $row[`clients`.'name']; ?> ;
What is returned in Chrome and Firefox debuggers is, "Uncaught syntax error: Unexpected token <". The debugger shows: var txt = <br />
I've tried enclosing the php script in single quotes, double quotes, and without quotes, and still no luck. Any thoughts, anyone?
About an hour later--> I found a workaround. I tried all of your suggestions, but none worked in this instance. var_dump and json_encode confirmed what I knew already, that the returned data was valid. Regardless of any of the variations in syntax, they all returned the same error. What I did was to apply the same syntax as above, but in a hidden input:
<input type="text" id="cName" hidden value="<?php echo $row[`clients`.'name']?>" />
Then changed the javascript code to this:
var txt = document.getElementById('cName').value;
Everything else works perfectly. Of course, I still have lingering thoughts about the use of backticks, and would prefer that I had a better, and safer code. As I mentioned somewhere, I simply copied the sql syntax directly from phpMyAdmin. In this instance, if I substitute single quotes for the backticks, the input returns nothing. Well, thanks all. If anyone wants to contribute more, I'll be glad to hear about it.
That's illegal PHP syntax, and very dangerous syntax in general. Try doing a var_dump($row) to see exactly what's in that array. Probably you want something more like
var txt = <?php echo json_encode($row['clients.name']); ?>;
instead.
Note the use of json_encode(). This will ENSURE that whatever you're spitting out in the JS code block is actually syntactically valid javascript.
e.g. consider what'd happen if you ended up with
var txt = Miles O'Brien;
^^^^^--undefined variable;
^--- another undefined var
^--- start of a string
^^^^^^^---unterminated string.
with json_encode(), you end up with
var txt = "Miles O'Brien";
and everything's a-ok.
var txt = "<?php echo $row['clients']['name']; ?>";
var txt = <?php echo $row[`clients`.'name']; ?> ;
Consider how PHP parses this:
var txt = is to be output directly to the client.
Enter PHP mode.
echo the following expression.
Evaluate $row[`clients`.'name'].
First we need to determine the array index, which is the concatenation of `clients` and 'name'.
Backtick in PHP is the execution operator, identical to shell_exec(). So PHP attempts to execute the shell command clients, which probably fails because that isn't what you intended and it doesn't exist. Consequently, at this stage, PHP outputs an HTML error message, starting with a line break <br />.
Your client now has var txt = <br /> (you can verify this by inspecting the HTML source of the page returned to your browser), which it attempts to evaluate in its JavaScript context. This gives rise to the "unexpected token" error that you have witnessed.
As others have mentioned, you probably meant to do something like $row['clients']['name'] or $row['clients.name'] instead—but without seeing the rest of your PHP, it's impossible to be sure. Also, as #MarcB has observed, you need to be certain that the resulting output is valid JavaScript and may wish to use a function like json_encode() to suitably escape the value.
The error comes from the fact that your return value (a string in javascript) must be in quotes.
Single quotes will take whatever is between them literally, escapes (like \n ) will not be interpreted, with double quotes they will.
var txt = "<?php echo $row['clients']['name']; ?>";
is what you want
Change this
var txt = <?php echo $row['clients'.'name']; ?> ;
to this:
var txt = <?php echo $row['clients']['name']; ?> ;

Catching php mysql variable in javascript

Im wondering how to catch mysql row in javascript, i tried to do that this way:
var x = <?php
mysql_connect(Not important);
mysql_select_db(not important);
$zapytanie = "SELECT (times) FROM dane WHERE email='$email'";
$idzapytania = mysql_query($zapytanie);
$wiersz = mysql_fetch_row($idzapytania);
echo $wiersz[0];
mysql_close (notimportant);
?>;
alert(x);
But this is not working. Any solutions? Sorry if this questions seems to be lame but i not the best in php/js, but have few things to do.
You should enclose the output of PHP in single quotes if you want it to be treated as a string in javascript. Like this:
var x = '<?php
mysql_connect(Not important);
mysql_select_db(not important);
$zapytanie = "SELECT (times) FROM dane WHERE email=\'$email\'";
$idzapytania = mysql_query($zapytanie);
$wiersz = mysql_fetch_row($idzapytania);
echo $wiersz[0];
mysql_close (notimportant);
?>';
Or alternatively, replace echo $wiersz[0]; for echo "'". $wiersz[0] ."'";
Try this
<?php
mysql_connect(Not important);
mysql_select_db(not important);
$zapytanie = "SELECT (times) FROM dane WHERE email='$email'";
$idzapytania = mysql_query($zapytanie);
$wiersz = mysql_fetch_row($idzapytania);
$w=$wiersz[0];
mysql_close (notimportant);
?>;
<script>
var x =<?php echo $w ?>
alert(x);
</script>
If you want to pass an array from PHP to jquery/javascript, the best way would be using JSON. Pseudocode:
var x=JSON.parse(<?php echo json_encode($array); ?>);
<script type="text/javascript">
setVariables('<?php echo $tag_name ?>', '<?php echo $client_id ?>');
</script>
and then creating that function in your .js file to utilize those values and do what you need.
function setVariables(name, id){
var tag_name = name
var client_id = id
//Operations that need these values.
}
write bundles to javascript!
Personally whenever transferring initilisation data from PHP to the client I find it best to combine the data into an array, and use casting and json_encode (as per Helpful's answer) to make a final structure that is nice and easy to use on the JavaScript side. This saves echoing different variables all over the place, and will automatically handle any type and escape syntax that is required i.e. wrapping strings with quotes, or back-slashing internal quotes in strings.
<?php
$export = array();
mysql_connect(Not important);
mysql_select_db(not important);
$zapytanie = "SELECT (times) FROM dane WHERE email='$email'";
$idzapytania = mysql_query($zapytanie);
$wiersz = mysql_fetch_row($idzapytania);
mysql_close (notimportant);
$export['x'] = !empty($wiersz[0]) ? $wiersz[0] : 'default';
?>
var data = <?php echo json_encode((object) $export); ?>;
Obviously the above is a little overkill for just one small value, however, if there ever became more than one value — something that could quite easily happen after further coding — it would be very easy to extend:
$export['x'] = !empty($wiersz[0]) ? $wiersz[0] : 'default';
$export['something_else'] = 54321;
Then all you need do to access these values in JavaScript is:
data.x
data.something_else
why use an array and why cast to an object?
The reason why I use an associative Array on the PHP side is because I find writing to arrays cleaner in PHP than Objects — not a huge fan of the -> notation. Also instantiating an Array is easier and seemingly more native than an Object in many versions of PHP. I then cast to an object before writing to JavaScript because I find the opposite is true in JavaScript, it's easier and nicer to read when accessing objects rather than arrays. This is all personal taste however.
NOTE: When defining your keys in the $export array you should be wary to keep to standard variable naming conventions i.e. either use camelCase/interCaps or convert spaces to underscores. Whilst you can get away with using any characters, even spaces, it will mean accessing the data from the JavaScript side becomes more cumbersome.
another thing to bear in mind
When setting variables in JavaScript it's often seen as a bad thing to pollute the global namespace. This basically means writing variables at the top level of run-time, that attach to themselves to global Object (usually Window), so that they are accessible by every bit of JavaScript code that runs in that execution. It is seen as bad because unless you use a likely unique variable name, collisions with other code can occur i.e. if both bits of code rely on the same global variable.
If you just output your data var at the top of your script it will become part of the global namespace, and using something as bland as data would be a prime example of something to avoid. It may not matter at all for small projects that aren't going to be extended or worked on by multiple coders, but it is always a good idea to get into the habit of avoiding this.
You can of course just use a variable name that is more unique to your project e.g. myProjectData, or if you have an over-arching namespace that defines your project i.e. examples of which would be jQuery, JSON, console; you could attach it to that e.g. Project.data.
However, if you wanted a more general approach you can also do this by wrapping your JavaScript code in an anonymous function.
<?php
$export = array();
$export['random_value'] = 'Where\'s my monkey?';
?>
(function( data ){
/// data will only be available inside this function
/// or to other sub functions defined inside this function.
console.log(data.random_value);
})(<?php echo json_encode((object) $export); ?>);
With the above code you should end up with your JavaScript always having a nice bundle of values to access, properly escaped and formatted, that have come straight from PHP in an easy way, and that doesn't pollute the global namespace.
WARNING: Obviously it should be noted that if you use the above anonymous wrapper method and you call in any other script files within your page, they wont be able to access data unless you pass the object to that code in some way. This is why people often prefer to have an over-arching namespace object for their project i.e. MyProject.data. However you do not necessarily have to do this — due to the benefit of having all your values bundled up in a singular JavaScript object — because passing it to other code is as simple as sending one variable as a parameter to a function i.e. other.code(data)

Javascript can't find my mod_rewrite query string!

I use the following javascript class to pull variables out of a query string:
getUrlVars : function() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
So this works: http://example.com/signinup.html?opt=login
I need http://www.example.com/login/ to work the same way. Using mod_rewrite:
RewriteRule ^login/? signinup.html?opt=login [QSA]
allows the page to load, the javascript to load, the css to load, but my javascript functions can't find the opt key (i.e., it's undefined). How do I get opt to my javascript?
Javascript is client-side. Mod_rewrite is server-side.
Therefore Javascript will never see the rewritten URL. As far as your browser is concerned, the URL that you entered is the finished address.
The only real solution is to change your Javascript so it looks at the URL it's got rather than the old version (or possibly parse for both alternatives, since the old URL will still work and people may still have old bookmarks).
The other possible solution would be to go to your server-side code (PHP? whatever?) where you can see the rewritten URL, and insert some javascript code there which you can parse on the client side. Not an ideal solution though. You'd be better of just going with option 1 and changing you Javascript to cope with the URLs it's actually going to be getting.
Your issue is that JavaScript runs on the client side, so it will never see the ?opt=login part to which the URL gets converted internally on the server.
Apart from changing your regular expression to match the new URL format, the easiest workaround might be to write a JavaScript statement on server side that introduces the value of the opt variable into JavaScript.
If you're using PHP, you can have the PHP create a JavaScript variable for you. For example:
$params = "?";
foreach($_GET as $key => $value) {
$params = $params . $key . "=" . $value . "&";
}
echo 'var urlParams = "' . $params . '"';
Now, you JavaScript will have access to a urlParams variable that looks like this
?opt=login&
Then, in your Javascript code, wherever you expected to use the URL parameters, use the urlParams instead.
If it's a special case, then put it as a special case in some way. If you rewrite generally, change your general regular expression. The way mod_rewrite works, the client never knows the rewritten URL. From the client, it's /login/ and /login/ only. Only the server ever knows that it's really signinup.html?opt=login. So there's no way your regular expression or location.href can know about it.
Unless you use the [R] flag in your RewriteRule, the browser (and thus javascript) will never know about the new URL. If you don't want to be redirecting people, you're going to have to add some code to your login page that GET parameters as javascript in the page.

Categories