Welcome to the Cumulus Support forum.

Latest Cumulus MX V3 release 3.28.6 (build 3283) - 21 March 2024

Cumulus MX V4 beta test release 4.0.0 (build 4017) - 17 March 2024

Legacy Cumulus 1 release v1.9.4 (build 1099) - 28 November 2014 (a patch is available for 1.9.4 build 1099 that extends the date range of drop-down menus to 2030)

Download the Software (Cumulus MX / Cumulus 1 and other related items) from the Wiki

PHP Source listing suggestion

Other discussion about creating web sites for Cumulus that doesn't have a specific subforum

Moderator: daj

Post Reply
sfws
Posts: 1183
Joined: Fri 27 Jul 2012 11:29 am
Weather Station: Chas O, Maplin N96FY, N25FR
Operating System: rPi 3B+ with Buster (full)

PHP Source listing suggestion

Post by sfws »

The PHP parser runs on the web server, converting a source PHP script to pure HTML and the browser only sees that resulting HTML web page, so if you ask the browser to display the page source it only shows generated HTML, not the source PHP script.

This is generally useful in that it allows the programmer to include reference in the PHP to items (such as access to databases) that you might not want end-users to see, and it protects the interllectual property of that programmer/designer/company because people cannot easily steal your script and fail to give you any credit.

However, programmers sometimes are happy to share their scripts and if there is just one they wish to share, it may therefore include a self down-loader, like the one I quote directly below, so that by entering a particular query-string ("?source=view" in this case) an end-user can see the PHP source:

Code: Select all

if ( isset($_REQUEST['source']) && strtolower($_REQUEST['source']) == 'view' ) {
 $filenameReal=__FILE__;
 $download_size=filesize($filenameReal);
 header('Pragma: public');
 header('Cache-Control: private');
 header('Cache-Control: no-cache, must-revalidate');
 header('Content-type: text/plain');
 header('Accept-Ranges: bytes');
 header("Content-Length: $download_size");
 header('Connection: close');
 readfile($filenameReal);
 exit;
}
PROBLEM - Multiple scripts used to produce one web page
One major disadvantage is that typically the main PHP script generating a web page will use one or more "require ..." and/or "include ..." instructions that bring in snippets of common code onto the page (e.g. for the access to database, for standard header or footer content, or to bring in shared functions or shared arrays). If you try each of the query-strings I have just quoted on a page you are looking at on the internet, it may be ignored and the page just reloaded, it might list the main script producing the web page, or it might list the first included script that contains a self-downloader snippet. It depends which script file includes the above code, and if more than one of the php script files includes the above code, the first file parsed that includes the code is actually listed. What you are never able to do is choose which file, if any, will have its source listed!

PROBLEM - Inconsistency in which query-string works
The biggest problem in my view is that there does not appear to be consistency over the query-string used to initiate the source list, the above example uses "source=view" as in cumulswebtags.php?source=view.

One major contributor to this forum uses "sce" as the value and 'view' as the attribute (rather than the value as in previous example) e.g. "https://weather.wilmslowastro.com/test/ ... p?view=sce". Another contributor uses "sce" as the attribute (not value as in previous example), and uses "show" as the value, i.e. the query-string to add is ?sce=show

Another major contributor on this forum uses 'view' as the name with a more obscure value "?view=getorfmiland" if you want to see the source of his widely used viewtopic.php?f=14&t=11397 script.

Other scripts use yet more variants including the reverse of the first example "view=source", abbreviated query-string names such as "sce=view", "scr=dump", and even "view=src". In general there is no way to guess what query-string to try. Sometimes trying the wrong query-string will load the web page as normal, sometimes it will cause the display of a message that is designed to put you off any more attempts.

PROPOSED SOLUTION
For my own scripts, I am happy to share some sources but wish to hide others. So I have devised an approach that lets you include in each script that is to be shared a snippet of code that downloads just that script if you mention the basename of that script in the query-string. This snippet is a call to a function available to all my scripts that includes
the instructions to read the relevant script and output it. Those scripts that contain passwords, or where I don't want to share my interlectual property, do not include any calls to the function (and are located in directories that are not visible to the browser). Because there is no standard query-string keyname, the snippet I include in many scripts allows for any one of several different selectors to be used, so people have to the best possible chance of picking a query-string that works. Furthermore, I have provided a way for my scripts tell you what query string to use if you want to see the PHP source. Consequently, I now have a better system that will allow people to list most of the other scripts that are included within my main web-page producing scripts.

My alternative, way to view the source of any of the scripts making up any web page, is shared below, in the vain(?) hope that others might consider it as 'best practice' to adopt for their script writing. As I report at viewtopic.php?f=10&t=4444#p127326, I have by incorporating my script snippets described below made it possible for you to display the source of any of my METAR decoding scripts that are being used on PaulMy's web site.
Let me just repeat the advantages of my approach:
* I wanted to be able to decide script by script whether its source could be viewed (to exclude those containing passwords or other material that you would expect to remain hidden).
* I wanted to be able to choose which of the various scripts in any web page got listed by selecting the relevant script using a query-string.
* I wanted a way to optionally list the range of possible query-strings (for when I could not remember which scripts were included in a particular web page).
* I needed the downloader to know the path names for each file as my individual scripts are not all in the same directory.
* I wanted to test whether files and functions existed, so that failure to find the down-loader did not affect the working of the rest of the script.

My solution consists of two parts. First a snippet of PHP instructions that I actually paste into each of the PHP scripts that the end-user is allowed to view:

Code: Select all

	#--------------------------------------------------------------------------
	# 	Just list the PHP source?	 Start of common SPAWS snippet.		
	#	 Modify URL of calling web page by adding a query-string such as 
	# 	?viewSource='xxxxx'" or "?src='xxxxx'" or "?sce='xxxxx'" 			
	# to see source for any file xxxxx.php whether main scriptor included file  
	#--------------------------------------------------------------------------
	$path = /* put the path to where you have the common script here */;
	if(file_exists($path . '\sourceView.php')) 	include_once $path . '\sourceView.php';		
	if(function_exists('add_source')) add_source(__FILE__, basename(__FILE__, '.php'));  # NB use of this magic constant represents the file in which it appears
		if(
					  // $_GET only returns parameters as part of a GET REQUEST, this is the one where (when you start (re-)loading the file), you read information from the query-string
					 // $_POST only returns parameters as part of a POST request, this is when a form has been completed its contents are kept in HTTP for when page reloaded
					// $_REQUEST will return parameters found in COOKIE, GET or POST
			(isset($_GET['viewSource']) && $_GET['viewSource'] == basename(__FILE__, ".php")) or
			(isset($_REQUEST['sce']) && $_REQUEST['sce'] == basename(__FILE__, '.php'))  or
			(isset($_REQUEST['scr']) and $_REQUEST['scr'] == 'dump' || $_REQUEST['scr'] == 'view') or
			(isset($_REQUEST['src']) && $_REQUEST['src'] == basename(__FILE__, '.php'))		
		){
				if(function_exists('display_source'))	display_source (basename(__FILE__, '.php'));
		}
	#----------------------------------------------------------
	# 	End of common snippet to list source call			
	#-----------------------------------------------------------
Note that I recognise that there is not going to be agreement as to which query-string selector is used so to make it easy to list my sources, I therefore offer multiple different selector name alternatives:
*viewSource=(base file name)
*src=(base file name)
*sce=(base file name)

I did consider including 'dump' as a attribute rather than a value, but the forum contributor who uses that has it as a value rather than an attribute, and I was determined to offer different attributes, but for consistency to always keep the base file as the value part of the query-string. Plus it makes sense, this is a source listing mechanism where you choose which file to list, so the file name must be the value.

The second part is in a separate file, the "include_once $path . '\sourceView.php';" in the above snippet loads it. Because so many of my PHP scripts use it, my "sourceView.PHP" includes several array and function declarations that I find useful to save me typing them multiple times into individual scripts (thus simplifying maintenance and update), but it does not include the snippet above as I choose not to allow people to read its own content! However, it basically has the down-loader that I quoted at the start of this post and I show most of the code below as I would be pleased if this was used more widely to make it easier for amateurs experimenting with programming like myself to see code.

However, it did need an eureka moment for me to work out that I could deal with my path-name uncertainty by storing the path name in an array together with a shorter-name appropriate to use in a query-string, so while I am happy for anybody else to use my script snippet, please don't use my path name idea for your own profit!

The two functions add_source(x,y) and display_source(y) referenced in the snippet above are also defined together with 2 global arrays. One array links basenames that can appear in a query-string with the full paths. The other array allows me to be prompted with list of query-strings available:

Code: Select all

function add_source($pathName,$fileName)
 {
	global $list_sources_available, $fileNameArray, $list_query_string;
	// if arrays not yet set up, define  now
		if(!isset($fileNameArray)) 
		{
			$list_query_string 	= array();
			$fileNameArray 	= array();
			# echo ' arrays defined <br>';
		}
			
	 // If current script not already in array, add it
		if (!isset($fileNameArray) or !in_array($fileName, $fileNameArray))
		{
			$fileNameArray["'" . $fileName . "'"] = "'" . $pathName . "'";
			# echo "<small>Use query-string <span class='blue'>?src=" . $fileName ."</span> to output PHP source for " . $pathName ." &nbsp; &nbsp; </small>\r\n";
		}
			
	
	// Note shared array holding path-names and file-names, and note optional variable which if included in calling script will produce output in final global array
	#if(isset($list_sources_available))	
		$list_query_string[] = "<small>Use query-string <span class='blue'>?src=" . $fileName ."</span> to output PHP source for " . $pathName ." &nbsp; &nbsp; </small>";
	// Tailor the 'src' to whatever you prefer
}

function display_source($filenameRequest)	{
	global $fileNameArray, $list_query_string; // see other function for how these arrays set up
	   echo "\r\n" . '==============================================================================================================================================';
		echo "\r\n Start of 'display_source' function for the PHP script '" . $filenameRequest . "' now entered.";
	   echo "\r\n" . '==============================================================================================================================================';
	# print_r($list_query_string);
	# print_r($fileNameArray);
	setlocale(LC_ALL, '');
	$pathAndFileNameShow 	= $fileNameArray["'$filenameRequest'"];
	# echo "\r\n Recognised that script requested for listing is " . $pathAndFileNameShow;
	$pathLength = strlen($pathAndFileNameShow) - strlen($filenameRequest) - 7;
	# echo "\r\n path length is " . $pathLength;
	$dirShow =  substr($pathAndFileNameShow, 1, $pathLength);	
	# echo "\r\n Directory extracted is '" . $dirShow . "'";
	$basename =   $filenameRequest . '.php';
	# echo "\r\n basename extracted is '" . $basename . "'";
	$currDir = getcwd();
	echo "\r\n current directory was " . $currDir;
	chdir(substr($pathAndFileNameShow, 1, $pathLength));
	$currDir = getcwd();
	echo "\r\n current directory is now " . $currDir;
	echo is_dir($currDir) ? ' (directory recognised) ' : ' (directory not recognised) ';
	opendir($currDir);
	
        $download_size = filesize($filenameRequest . '.php');
	   echo "\r\n file size determined as " . $download_size;
        header('Pragma: public');
        header('Cache-Control: private');
        header('Cache-Control: no-cache, must-revalidate');
        header("Content-type: text/plain");
        header("Accept-Ranges: bytes");
        header("Content-Length: $download_size");
        header('Connection: close');
	   echo "\r\n" . '==============================================================================================================================================';
		echo "\r\n Your requested PHP source Listing for " . $pathAndFileNameShow . ' begins now';
	   echo "\r\n" . '==============================================================================================================================================';
	   echo "\r\n";
		readfile($filenameRequest . '.php',true);
    exit;
}
If you want to download the exact script I use (slightly simplified from that described above) find one of my PHP scripts I have shared.
The first script at viewtopic.php?f=18&t=18096&p=142634#p142634 is actually multiple scripts driving one web page and demonstrates what I mean rather nicely.
Post Reply