Loading Javascript through PHP - php

From a tutorial I read on Sitepoint, I learned that I could load JS files through PHP (it was a comment, anyway). The code for this was in this form:
<script src="js.php?script1=jquery.js&scipt2=main.js" />
The purpose of using PHP was to reduce the number of HTTP requests for JS files. But from the markup above, it seems to me that there are still going to be the same number of requests as if I had written two tags for the JS files (I could be wrong, that's why I'm asking).
The question is how is the PHP code supposed to be written and what is/are the advantage(s) of this approach over the 'normal' method?

The original poster was presumably meaning that
<script src="js.php?script1=jquery.js&scipt2=main.js" />
Will cause less http requests than
<script src="jquery.js" />
<script src="main.js" />
That is because js.php will read all script names from GET parameters and then print it out to a single file. This means that there's only one roundtrip to the server to get all scripts.
js.php would probably be implemented like this:
<?php
$script1 = $_GET['script1'];
$script2 = $_GET['script2'];
echo file_get_contents($script1); // Load the content of jquery.js and print it to browser
echo file_get_contents($script2); // Load the content of main.js and print it to browser
Note that this may not be an optimal solution if there is a low number of scripts that is required. The main issue is that web browser does not load an infinitely number of scripts in parallel from the same domain.
You will need to implement caching to avoid loading and concatenating all your scripts on every request. Loading and combining all scripts on every request will eat very much CPU.
IMO, the best way to do this is to combine and minify all script files into a big one before deploying your website, and then reference that file. This way, the client just makes one roundtrip to the server, and the server does not have any extra load upon each request.
Please note that the PHP solution provided is by no means a good approach, it's just a simple demonstration of the procedure.

The main advantage of this approach is that there is only a single request between the browser and server.
Once the server receives the request, the PHP script combines the javascript files and spits the results out.
Building a PHP script that simply combines JS files is not at all difficult. You simply include the JS files and send the appropriate content-type header.
When it gets more difficult is based on whether or not you want to worry about caching.
I recommend you check out minify.

<script src="js.php?script1=jquery.js&scipt2=main.js" />
That's:
invalid (ampersands have to be encoded)
hard to expand (using script[]= would make PHP treat it as an array you can loop over)
not HTML compatible (always use <script></script>, never <script />)
The purpose of using PHP was to reduce the number of HTTP requests for JS files. But from the markup above, it seems to me that there are still going to be the same number of requests as if I had written two tags for the JS files (I could be wrong, that's why I'm asking).
You're wrong. The browser makes a single request. The server makes a single response. It just digs around in multiple files to construct it.
The question is how is the PHP code supposed to be written
The steps are listed in this answer
and what is/are the advantage(s) of this approach over the 'normal' method?
You get a single request and response, so you avoid the overhead of making multiple HTTP requests.
You lose the benefits of the generally sane cache control headers that servers send for static files, so you have to set up suitable headers in your script.

You can do this like this:
The concept is quite easy, but you may make it a bit more advanced
Step 1: merging the file
<?php
$scripts = $_GET['script'];
$contents = "";
foreach ($scripts as $script)
{
// validate the $script here to prevent inclusion of arbitrary files
$contents .= file_get_contents($pathto . "/" . $script);
}
// post processing here
// eg. jsmin, google closure, etc.
echo $contents();
?>
usage:
<script src="js.php?script[]=jquery.js&script[]=otherfile.js" type="text/javascript"></script>
Step 2: caching
<?php
function cacheScripts($scriptsArray,$outputdir)
{
$filename = sha1(join("-",$scripts) . ".js";
$path = $outputdir . "/" . $filename;
if (file_exists($path))
{
return $filename;
}
$contents = "";
foreach ($scripts as $script)
{
// validate the $script here to prevent inclusion of arbitrary files
$contents .= file_get_contents($pathto . "/" . $script);
}
// post processing here
// eg. jsmin, google closure, etc.
$filename = sha1(join("-",$scripts) . ".js";
file_write_contents( , $contents);
return $filename;
}
?>
<script src="/js/<?php echo cacheScripts(array('jquery.js', 'myscript.js'),"/path/to/js/dir"); ?>" type="text/javascript"></script>
This makes it a bit more advanced. Please note, this is semi-pseudo code to explain the concepts. In practice you will need to do more error checking and you need to do some cache invalidation.
To do this is a more managed and automated way, there's assetic (if you may use php 5.3):
https://github.com/kriswallsmith/assetic
(Which more or less does this, but much better)
Assetic
Documentation
https://github.com/kriswallsmith/assetic/blob/master/README.md
The workflow will be something along the lines of this:
use Assetic\Asset\AssetCollection;
use Assetic\Asset\FileAsset;
use Assetic\Asset\GlobAsset;
$js = new AssetCollection(array(
new GlobAsset('/path/to/js/*'),
new FileAsset('/path/to/another.js'),
));
// the code is merged when the asset is dumped
echo $js->dump();
There is a lot of support for many formats:
js
css
lot's of minifiers and optimizers (css,js, png, etc.)
Support for sass, http://sass-lang.com/
Explaining everything is a bit outside the scope of this question. But feel free to open a new question!

PHP will simply concatenate the two script files and sends only 1 script with the contents of both files, so you will only have 1 request to the server.

Using this method, there will still be the same number of disk IO requests as if you had not used the PHP method. However, in the case of a web application, disk IO on the server is never the bottle neck, the network is. What this allows you to do is reduce the overhead associated with requesting the file from the server over the network via HTTP. (Reduce the number of messages sent over the network.) The PHP script outputs the concatenation of all of the requested files so you get all of your scripts in one HTTP request operation rather than multiple.

Looking at the parameters it's passing to js.php it can load two javascript files (or any number for that matter) in one request. It would just look at its parameters (script1, script2, scriptN) and load them all in one go as opposed to loading them one by one with your normal script directive.
The PHP file could also do other things like minimizing before outputting. Although it's probably not a good idea to minimize every request on the fly.
The way the PHP code would be written is, it would look at the script parameters and just load the files from a given directory. However, it's important to note that you should check the file type and or location before loading. You don't want allow a people a backdoor where they can read all the files on your server.

Related

BIRT 4.5 - Disable saving connectstring inside report.rptdesign, PHP to assign connectstring

I am using Birt 4.5 and PHP/MYSQL.
I am able to run birt reports with php. I have enabled tomcat and copied 'birt-runtime-4_5_0/WebViewerExample' to tomcat/webapps and renamed it to birt.
So I can run birt viewer with php;
<?php
$fname = "report/test.rptdesign&__showtitle=false";
$dest = "http://localhost:8081/birt/frameset?__report=";
$dest .= $fname;
header("Location: $dest" );
?>
Above code is working fine. But report connectstring already saved in test.rptdesign file.
I want to remove DB login credentials from test.rptdesign file and assign it while report open with PHP.
I have tried with report parameters. But all the parameters will display on browser address-bar.
Is there any secure way to do this? This is very important when we need to change the database location. It is very hard to change the data source of each and every .rptdesign file.
Thank You,
Supun
I don't believe using report parameters to handle a database connection is the right way. In addition to the address-bar problem you mentionned, it will cause unexpected issues: for example you won't be able to use this database to feed the dataset of another report parameter.
With Tomcat the best approach is to externalize the database connection in a connection pool: easy, robust, and reports might run significantly faster.
Alternatively the datasource can be externalized in a BIRT library (.rptlibrary) and shared across all report-designs: thus only the library needs to be updated when the database location is changing.
I agree with Dominique that sending the database parameters via the query is most likely an inappropriate solution - and you've not given any explanation of whether this is a requirement of the system.
But it is quite trivial to proxy the request via PHP and decorate the URL with the required parameters, something like...
<?php
$_GET['__showtitle']=$_GET['__showtitle'] ? $_GET['__showtitle'] : 'false';
$_GET['__report']=$fname; // NB this should be NULL in your code!
$_GET['dbuser']='a_db_user';
$_GET['passwd']='s3cr3t';
$qry=http_build_query($_GET);
$url="http://localhost:8081/birt/frameset?" . $qry;
// if its simply returning HTML, then just....
$fin=fopen($url, 'r');
while ($l=fgets($fin)) {
print $l;
}
exit;
If the returned content contains relative links the you'll need to rewrite the output stream. If the content type is unusual or you want to project other headers (e.g. for caching) to the browser, then you'll need to use Curl, capture the headers and relay them.

Save binary request body as file

I wrote a program that reads a binary file into the RAM and then sends it using an HTTP request to my server. It uses the PUT method and the binary file is (in) the body.
Now how can I tell my server to receive and safe the file in a folder?
If possible without any additional libraries that I would need to download (unless it's more efficient).
I know, there are some similar threads to this one, but they either they where about receiving text or they were about doing it with libraries or there simply was no sufficient answer.
I'd also like to know, if it would be more efficient or smarter to use the POST method or any other instead of PUT.
You can get at the data by opening a stream to php://input, like so:
$datastr = fopen('php://input',rb);
if ($fp = fopen('outputfile.bin', "wb")){
while(!feof($datastr)){
fwrite($fp,fread($datastr,4096)) ;
}
}
As to whether to use POST or anything else depends on what is happening with the data, and whether you care about being RESTful or such. See other questions/answers, indempotency.
The advantage I would see with using POST is that it's more commonly used (on most submission forms where you upload a file), and therefore has more support from within PHP and html.

PHP equivalent of ASP.NET Application/Cache objects

My Google-fu hasn't revealed what I'm looking for, so I'm putting this one out to the crowd.
Coming from an ASP.NET development background, I'm used to having the Application and Cache collections available for me to stash rarely-modified but often-used resources (such as lookup rows from a database or the contents of static XML documents) in the memory of the web server, so I don't have to reload these often-used items during every request.
Does PHP have an equivalent? I've read up briefly on the memcache extension, but this won't work for me (as I don't have control over the server configuration.) I'm tempted to implement something that would allow me to pre-parse or pre-select the resources and generate a sort of PHP cache "file" that would construct the cached object from literals stored in the file, but this seems like a very hacky solution to me.
Is there something in PHP (or, alternatively, a helper library of some sort) that will allow me to accomplish this using best practices?
In short, no, such a thing is not available natively in PHP. To understand why, you have to understand that PHP has its entire environment built for each request, and it is subsequently torn down at the end of the request. PHP does give you $_SESSION to store per session variables, but after digging into the docs you will see that that variable is built during each request also. PHP (or mod php to be more specific) is fundamentally different from other "application servers". Basically, it is not an application server. It is a per request script runner.
Now, don't get me wrong, PHP lets you do application level data store, but you will have to go to a database, or to disk to get it. Remember this though, don't worry about optimizing for performance until it is shown that preformance is a problem. And I will guess that 99 times out of 100, by the time performance is an issue that isn't due to some poor code you wrote, you will have the resources to build your own pretty little memcached server.
Take a look at Zend_Cache library, for example. It can cache in multiple backends.
This is a bit of a hack but but works in php 7+
Basically you cache your data to a temp file and then use include to read the file, which is cached in memory by the php engine’s in-memory file caching (opcache)
function cache_set($key, $val) {
$val = var_export($val, true);
// HHVM fails at __set_state, so just use object cast for now
$val = str_replace('stdClass::__set_state', '(object)', $val);
// Write to temp file first to ensure atomicity
$tmp = "/tmp/$key." . uniqid('', true) . '.tmp';
file_put_contents($tmp, '<?php $val = ' . $val . ';', LOCK_EX);
rename($tmp, "/tmp/$key");
}
And here’s how we “get” a value from the cache:
function cache_get($key) {
#include "/tmp/$key";
return isset($val) ? $val : false;
}
from https://medium.com/#dylanwenzlau/500x-faster-caching-than-redis-memcache-apc-in-php-hhvm-dcd26e8447ad

PHP variables maintaining an URL string

I'm not a PHP developer, but I'm currently hacking on an internal tool so my team can take advantage of its goodness. There's an index file that looks like so:
require( ($loader_path = "../../loaderapi/") . "loader.php" );
Used like this, $loader_path will retain its value within the loader.php file.
However, we want to access this API from our team's server like so:
require( ($loader_path = "http://remoteservername/loaderapi/") . "loader.php" );
In this case the $loader_path variable doesn't retain its value. I'm guessing it has something to do with it being a full blown URL, but I might be wrong. Any idea on how I can make this work, or why I can't do it this way?
If your accessing a PHP script over HTTP, only the output of that script is returned. So your script will try to interpret the output of that remote PHP script and not its source.
If there is a connection over the file system, you may want to try file://remoteservername/loaderapi/loader.php instead.
NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO!
Remote file inclusion is a BAD idea, probably one of the biggest security flaws you can open up. Even for an internal tool this is not acceptable even if only purely for contributing bad habits.
PHP by default disables this behavior, and there is a broad push to have the ability to perform an include on a URL completely stripped from PHP (as there is no compelling reason to have this ability).
If you want to load shared resources, go through a shared file system drive (as in, don't use http, ftp, anything but file://) or better yet distribute copies of loader.php through a version control system. Loading from a single file resource opens you up to problems in the future of say a new dev overwriting loader.php and breaking everyone else's code.
There shouldn't be any real difference between the two; what you're doing is defining $loader_path, concatenating the loader.php, and passing that to require.
HOWEVER: you're defining the variable within the scope of a require, which will halt processing of the script of require fails.
Try replacing 'require' with 'include' and see if it retains the variable.
Also, note that if you are running your PHP server on a windows machine, and the php version is less than 4.3.0, neither 'require' nor 'include' can handle remote files : http://us.php.net/manual/en/function.include.php
Also, as noted before, if the .php lives on a remote server that parses php, you will not get code, but the result of the remote server processing the code. You'll either have to serve it up as a .txt file, or write php that, when processed, outputs valid php.
Have you tried splitting it into two lines:
$loader_path = "http://remoteservername/loaderapi/";
require( $loader_path . "loader.php" );
It's easier to read this way as well.
Simplify the code reading by simply putting everything on 3 lines:
$loader_path = "http://remoteservername/loaderapi/";
$page = "loader.php";
require($loader_path . $page );
Much clearer and it works.
why not just put it above the require statement? would make it easier to read too.
<?php
$loader_path = "../../folderName/"
require($loader_path . "filename")
?>

What are the advantages to putting your Javascript in a .php file?

I occasionally come across pages where some Javascript is included via a PHP file:
<html>
<head>
<script type="text/javascript" src="fake_js.php"></script>
</head>
<body onload="handleLoad();">
</body>
</html>
where the contents of fake_js.php might look something like this:
<?php header('Content-type: text/javascript') ?>
function handleLoad() {
alert('I loaded');
}
What are the advantages (or disadvantages) to including Javascript like this?
It makes it easy to set javascript variables from the server side.
var foo = <?=$foo?>
I usually have one php/javascript file in my projects that I use define any variables that need to be used in javascript. That way I can access constants used on the server-side (css colors, non-sensitive site properties, etc) easily in javascript.
Edit: For example here's a copy of my config.js.php file from the project I'm currently working on.
<?php
require_once "libs/config.php";
if (!function_exists("json_encode")) {
require_once "libs/JSON.php";
}
header("Content-type: text/javascript");
echo "var COLORS = ". json_encode($CSS_COLORS) .";\n";
echo "var DEBUG = ". ((DEBUG == true) ? "true" : "false").";";
?>
If you don't need it, don't use it:
The first thing you need to keep in
mind is YAGNI. You Ain't Gonna
Need It. Until a certain feature,
principle, or guideline becomes useful
and relevant, don't use it.
Disadvantages:
Added complexity
Slower than static files.
Caching problems (server side)
Scalability issues (load balancers offload static files from the heavy PHP/Apache etc processes)
Advantages:
User specific javascript - Can be achieved by initializing with the right variables / parameters in the <head> </head> section of the HTML
Page specific javascript - JS could also be generalized to use parameters
JSON created from database (usually requested via AJAX)
Unless the javascript is truely unique (i.e. JSON, parameters/variables) you don't gain much. But in every case you should minimize the amount of JS generated on the server side and maximize the amount of code in the static files. Don't forget that if it's dynamic, it has to be generated/downloaded again and again so it's not wanted for it to be a heavy process.
Also:
This could also be used to minimize the amount of server configuration (for example if the web server doesn't serve file.js with the correct content type)
There's no benefit for the example you gave above (beyond peculiar deployment scenarios where you have access to .php files and not .js files, which would be insane but not unheard of).
That said, this approach allows you to pass the JS through the php parser - which means you can generate your JS dynamically based on server variables.
Agree with tj111. Apart from what tj mentioned, I also found php-generated javascripts a great weapon to fight the browser's caching tricks. Not that long ago I was cursing the whole javascript for its being constantly cached by the browser. Refreshing the page helped me not, had to clear the whole cache in order to force the browser to reload the javascript files. As soon as I built a php wall in front of my javascripts:
fake_js.php:
<?php
header('Content-type: text/javascript')
include('the_real_javascript.js');
?>
A fresh new javascript would always show up at the client side. However this approach is obviously only good in the development phase, when it can save the developer quite some headache to have the correct javascript loaded in the browser. Of course when connecting to localhost, the penalty of repeatedly loading the same file is not as big.
In a live web application/site client-side caching is welcome to reduce network traffic and overall server load.
Advantage (not PHP specific - I used this technique in EmbPerl and JSP) would be the ability to dynamically generate or tweak/customize the JavaScript code on the server side.
An example usage would be population of an array based on the contents of a DB table.
Or application of localization techniques.
If you don't have full server access and can't turn on gzip encoding then it's pretty useful to put the following in your javascript file (note: will need to be renamed to file.js.php or parsed as PHP through .htaccess directive):
<?php
ob_start( 'ob_gzhandler' );
header("Content-type: text/javascript");
?>
// put all your regular javascript below...
You could also use it for better cache control, visitor tracking, etc in lieu of server-controlled solutions.
Absolutely none, IMHO. I use a js framework that I wrote to handle the setting of whatever server-side variables I need to have access to. It is essentially the same as embedding PHP in JavaScript, but much less ambiguous. Using this method allows you to also completely separate server-side logic and html away from javascript. This results in much cleaner, more organized and lowly-coupled modular code.
You could do something like this in your html:
<script type="text/javascript">
registry = {
myString : '<?php echo $somePhpString; ?>',
myInt : <?php echo $somePhpInteger; ?>
}
</script>
And then do something like this in your js:
if (registry.myInt === 1) {
alert(registry.myString);
}

Categories