PHP - Customize .zip File Before Download? - php

So I am making a script where I want to learn how to limit use on one domain, but I need to modify the script before the download. My question is, I want to take a $_GET variable filled out by the user of their website. Customize a script with file_put_contents or something, and then download the modified script.. How would I go about this? Does it require Javascript and PHP, or just Javascript? I'm not sure how to go about it. An example of modifying a download can be found here

So, if I understood correctly, a user fill some form with a var (lets call it $var) and clicks the form's submit button to download a file (lets call it 'myscript.php').
You want to edit 'myscript.php' and put the $var inside that script before the user downloads it. Is this assumption correct?
For that you need to prepare your script beforehand by placing a placeholder somewhere and then, before the user downloads the file, you change the placeholder for the intended block of code. Alternatively you can replace the first <?php tag for your code, if that's relevant.
Mini Example:
myscript1.php
<?php
$varb = 'a string with DEFAULT VAR inside just to test';
//Block of code goes here
//{%%DEFAULT VAR%%}
print $var;
Code called by form:
<?php
$path = 'myscript1.php';
$file = file_get_contents($path);
$var = $_GET['var'];
$block = '
// valid php code that you put inside script (without <?php)
// Alternatively you can grab the block of code
// from a file with file_get_contents
$var = ' . $var . ';';
$file = str_replace('//{%%DEFAULT VAR%%}', $var, $file);
Here's a more complete (and complex) example...
myscript2.php
<?php
$var = '{%%DEFAULT VAR%%}';
$varb = 'another string with DEFAULT VAR inside just to test';
print $var;
Download script (called by the form)
<?php
$form =
'<html>
<head></head>
<body>
<form action="">
<span>myVar</span><input type="text" id="var" name="var"/><br/>
<input type="submit" value="download file"/>
</form>
</body>
</html>';
if (isset($_GET['var'])) {
$var = $_GET['var'];
$path = 'myscript2.php';
$file = file_get_contents($path);
// PART 1
/*
* Tokenizer Approach (read http://php.net/manual/en/book.tokenizer.php)
* Splits a php file into an Array with tokens (like the ZEND Engine Parser does)
* Usefull for parsing and validating the PHP file
* In this case we're just cheking if the script has
* $var = {%%DEFAULT VAR%%}; somewhere but you can implement a more complex code to check
* complete statements or instructions!!! This is just for example's sake!
* Skip this part if you don't need to validate the script
*/
$tokens = token_get_all($file);
if (!validatePHPScript($tokens)) {
throw new Exception("script didn't pass validation");
}
//END PART 1
// PART 2
/*
* The actual string replacement via str_replace
* It actually just replaces a placeholder for anything
* you want, in this case the $_GET['var'] value
* You can actually replace a placeholder for a complete
* block of code: just put the placeholder in the part you want
* to insert and then comment it. #{‰‰PLACEHOLDER_NAME%%}
* Then replace the placeholder with the comment tag
*
*/
$file = str_replace('{%%DEFAULT VAR%%}', $var, $file);
// END PART 2
//PART 3
/*
* Serve the file to download through headers
*/
header('Content-type: text/plain');
header('Content-disposition: attachment; filename=myscript.php');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . strlen($file));
ob_clean();
flush();
print $file;
// END PART 3
} else {
print $form;
}
validation function example:
//Validation example
function validatePHPScript(array $tokens)
{
$max = count($tokens);
$var_check = false;
$operator_check = false;
$string_check = false;
$semicolon_check = false;
// loop through all $tokens
for ($i = 0; $i < $max; ++$i) {
// only look for variables (tokens with type T_VARIABLE)
if (is_array($tokens[$i]) && $tokens[$i][0] === T_VARIABLE) {
// LOOK for a variable named $var
if ($tokens[$i][1] === '$var') {
// Found $var
$var_check = true;
// let's check if its an assignment statement
// by looping through the remaining code until we find a colon
for ($ii = $i +1; $ii < $max; ++$ii) {
// Look for the operator =
if ($tokens[$ii] === '=') {
$operator_check = true;
// Look for the string and check if it corresponds to the value
// we're going to replace
} else if ($operator_check && is_array($tokens[$ii]) && $tokens[$ii][0] === T_CONSTANT_ENCAPSED_STRING && $tokens[$ii][1] === "'{%%DEFAULT VAR%%}'") {
$string_check = true;
// Look for the statement end token (semicolon)
} else if($string_check && $tokens[$ii] === ';') {
$semicolon_check = true;
break;
}
}
// All checks passed so we don't need to loop anymore
if ($var_check && $operator_check && $string_check && $semicolon_check) {
return true;
} else {
// reset checks
$var_check = false;
$operator_check = false;
$string_check = false;
$colon_check = false;
}
}
}
}
return false;
}

Related

How could I check if there is code outside a class in php?

Let's say that you have a class in php with functions and all that. How could you check if there is no code outside the class?
I tried to code this checker with PHP and did it with regex and tokens but nothing worked for me :/
An exmple
<?php
class example {
var $name;
var $password;
function __construct($name, $password) {
$this->name = $name;
$this->password = $password;
}
----Allowed code----
}
----Not allowed code----
?>
EDIT: (SOLVED)
Thanks #user3163495 for all the information
Here what I did:
1º I tried to get the class name inside the file with this two functions:
function getClass($tokens) {
$clases = array();
for($i = 0; $i < count($tokens); $i++) {
//Tipo del token actual
$tokenName = getTokenName($tokens, $i);
if($tokenName === "T_CLASS") {
//Searchs the name that it has in the file.
return getClassName($tokens, $i);
}
}
return "";
}
function getClassName($tokens, $i) {
$index = $i + 1;
//Line in which is the class inside the file
$lineaClase = getTokenLine($tokens, $i);
//Line to be updated while searching
$lineaTemp = getTokenLine($tokens, $index);
//Type of token to be updated while searching
$tokenName = getTokenName($tokens, $index);
//Searchs in the parsed array for the first class token
while($index < count($tokens) &&
$lineaClase === $lineaTemp &&
($tokenName === "UNKOWN" || $tokenName === "T_WHITESPACE")) {
$index++;
$tokenName = getTokenName($tokens, $index);
$lineaTemp = getTokenLine($tokens, $index);
}
//Returns the name of the class
return getTokenContent($tokens, $index);
}
Then, I injected PHP code in the end of the file that I tried to check if it's only a class. Also I saved this new content in a new file called temp.php and finally I shell-executed this to get the echo of the injected code, that will correspond to beginning_of_class:end_of_class. Here is where I used what #user3163495 told me, thank you again.
function codeInjection($clase, $contenido) {
//PHP code to inject, thanks to #user3163495
$codigoPHP = "<?php \$class = new ReflectionClass(\"{$clase}\"); \$comienzo = \$class->getStartLine(); \$fin = \$class->getEndLine(); echo \$comienzo . \":\" . \$fin; ?>";
$contenido .= $codigoPHP;
//Creating temp file
file_put_contents("temp.php", $contenido);
//Returning result of execution
return shell_exec("php temp.php");
}
Further, I removed from the token parsed array those tokens which line where between the beginning and the end of the class. Last I go through the array searching for something that is different than a comment, white space, etc..
(Variables are in spanish, if you don't understand the meaning of some feel free to ask)
If you are wanting to "scan" the questionable file from another script to see if there is any code outside the class, then you could use the ReflectionClass in PHP.
Step 1: get the file name that your class is defined in
$class = new ReflectionClass("example");
$fileName = $class->getFileName();
Step 2: get the starting and ending lines of code that the class definition occupies in the file
$startLine = $class->getStartLine();
$endLine = $class->getEndLine();
$numLines = $endLine - $startLine;
Step 3: use file_get_contents() on the file name you obtained in Step 1, and see if there is any forbidden code before the start line or after the end line. You'll have to test and play around with what you get as I don't know exactly where getStartLine() and getEndLine() consider "start" and "end", respectively.
I hope you get the idea.
Some code lifted from this answer: https://stackoverflow.com/a/7909101/3163495

Call error according to request environment like GET or POST

My php script self describe every thing what want to do with this script
Environment #1
Request comes through POST by form from previous page action to below script
Environment #2
Request comes through GET for my clients to share download link for one use
Now every thing is perfect in below script but I want to call the error according to request environment like if GET request is invalid then error Your download code is invalid or expires and if POST request is invalid then error header ('location: ../Download-token')
please help
<?php
if(isset($_GET['dlCODE']) and ($_GET['Rfile'])){
$reqfname = $_GET['Rfile'];
$dlKEY = trim($_GET['dlCODE']);
$kfile = file('Download-Keys.php');
foreach($kfile as &$one) {
if(rtrim($one)==$dlKEY) {
$slink = true;
$one = '';
}
}
file_put_contents('Download-Keys.php', $kfile);
}
if(isset($_POST['Rf'])){
#session_start();
if(!isset($_SESSION['download-token'])){
header("location:../Downloads-Passing");
}
$reqfname = $_POST['Rf'];
$dlREQ = true;
}
if(($slink == true) or ($dlREQ == true)){
//Below Variables for Defines value hereinafter use;
$explode = explode('.',$reqfname);
$t = time();
$Clintfname = $explode[0]."_".$t.'.'.$explode[1];
$fPath = "../qd_files/";
//Below code for force to browser display save as dialogue box options;
header('Content-type: application/zip');
//Below code for rename the source file name to escape hot-linking;
header('Content-Disposition: attachment; filename='.$Clintfname);
//Below code for Sending correct file size to be ready to Download;
header('Content-Length: '.filesize($fPath.$reqfname));
//Below code for read original file from the source;
readfile($fPath.$reqfname);
//Below code for Count Download hit on download button;
$dlfile = "dlcounter.php";
$dlcoun = file_get_contents($dlfile);
/*PUT ADD ONE*/ file_put_contents($dlfile, ++$dlcoun);
} else {
/*
**
**
**
**
**
errors need here
**
**
**
**
**
*/
}
?>
you need define the error inside of each Environment, maybe:
<?php
$error = 0;
if(isset($_GET['dlCODE']) and ($_GET['Rfile'])){
$reqfname = $_GET['Rfile'];
$dlKEY = trim($_GET['dlCODE']);
$kfile = file('Download-Keys.php');
foreach($kfile as &$one) {
if(rtrim($one)==$dlKEY) {
$slink = true;
$one = '';
}else {$error = 1;}
}
file_put_contents('Download-Keys.php', $kfile);
}
if(isset($_POST['Rf'])){
#session_start();
if(!isset($_SESSION['download-token'])){$error = 2;}
$reqfname = $_POST['Rf'];
$dlREQ = true;
}
switch($error)
{
case 1: echo 'Your download code is invalid or expires'; Break;
case 2: header ('location: ../Download-token'); Break;
default:
//Below Variables for Defines value hereinafter use;
$explode = explode('.',$reqfname);
$t = time();
$Clintfname = $explode[0]."_".$t.'.'.$explode[1];
$fPath = "../qd_files/";
//Below code for force to browser display save as dialogue box options;
header('Content-type: application/zip');
//Below code for rename the source file name to escape hot-linking;
header('Content-Disposition: attachment; filename='.$Clintfname);
//Below code for Sending correct file size to be ready to Download;
header('Content-Length: '.filesize($fPath.$reqfname));
//Below code for read original file from the source;
readfile($fPath.$reqfname);
//Below code for Count Download hit on download button;
$dlfile = "dlcounter.php";
$dlcoun = file_get_contents($dlfile);
/*PUT ADD ONE*/ file_put_contents($dlfile, ++$dlcoun);
Break;
}

eJabberd with PHP extauth

I'm trying to make a PHP extauth script, i configured extauth in ejabberd.cfg and give permission to auth.php file, the script is the following
#!/usr/bin/php
<?php
error_reporting(0);
$auth = new JabberAuth();
$auth->dbhost = "";
$auth->dbuser = "";
$auth->dbpass = "";
$auth->dbbase = "";
$auth->play(); // We simply start process !
class JabberAuth {
var $dbhost; /* MySQL server */
var $dbuser; /* MySQL user */
var $dbpass; /* MySQL password */
var $dbbase; /* MySQL database where users are stored */
var $debug = true;/* Debug mode */
var $debugfile = "/var/log/pipe-debug.log"; /* Debug output */
var $logging = true; /* Do we log requests ? */
var $logfile = "/var/log/pipe-log.log" ; /* Log file ... */
/*
* For both debug and logging, ejabberd have to be able to write.
*/
var $jabber_user; /* This is the jabber user passed to the script. filled by $this->command() */
var $jabber_pass; /* This is the jabber user password passed to the script. filled by $this->command() */
var $jabber_server; /* This is the jabber server passed to the script. filled by $this->command(). Useful for VirtualHosts */
var $jid; /* Simply the JID, if you need it, you have to fill. */
var $data; /* This is what SM component send to us. */
var $dateformat = "M d H:i:s"; /* Check date() for string format. */
var $command; /* This is the command sent ... */
var $mysock; /* MySQL connection ressource */
var $stdin; /* stdin file pointer */
var $stdout; /* stdout file pointer */
function JabberAuth()
{
#define_syslog_variables();
#openlog("pipe-auth", LOG_NDELAY, LOG_SYSLOG);
if($this->debug) {
#error_reporting(E_ALL);
#ini_set("log_errors", "1");
#ini_set("error_log", $this->debugfile);
}
$this->logg("Starting pipe-auth ..."); // We notice that it's starting ...
$this->openstd();
}
function stop()
{
$this->logg("Shutting down ..."); // Sorry, have to go ...
closelog();
$this->closestd(); // Simply close files
exit(0); // and exit cleanly
}
function openstd()
{
$this->stdout = #fopen("php://stdout", "w"); // We open STDOUT so we can read
$this->stdin = #fopen("php://stdin", "r"); // and STDIN so we can talk !
}
function readstdin()
{
$l = #fgets($this->stdin, 3); // We take the length of string
$length = #unpack("n", $l); // ejabberd give us something to play with ...
$len = $length["1"]; // and we now know how long to read.
if($len > 0) { // if not, we'll fill logfile ... and disk full is just funny once
$this->logg("Reading $len bytes ... "); // We notice ...
$data = #fgets($this->stdin, $len+1);
// $data = iconv("UTF-8", "ISO-8859-15", $data); // To be tested, not sure if still needed.
$this->data = $data; // We set what we got.
$this->logg("IN: ".$data);
}
}
function closestd()
{
#fclose($this->stdin); // We close everything ...
#fclose($this->stdout);
}
function out($message)
{
#fwrite($this->stdout, $message); // We reply ...
$dump = #unpack("nn", $message);
$dump = $dump["n"];
$this->logg("OUT: ". $dump);
}
function myalive()
{
if(!is_resource($this->mysock) || !#mysql_ping($this->mysock)) { // check if we have a MySQL connection and if it's valid.
$this->mysql(); // We try to reconnect if MySQL gone away ...
return #mysql_ping($this->mysock); // we simply try again, to be sure ...
} else {
return true; // so good !
}
}
function play()
{
do {
$this->readstdin(); // get data
$length = strlen($this->data); // compute data length
if($length > 0 ) { // for debug mainly ...
$this->logg("GO: ".$this->data);
$this->logg("data length is : ".$length);
}
$ret = $this->command(); // play with data !
$this->logg("RE: " . $ret); // this is what WE send.
$this->out($ret); // send what we reply.
$this->data = NULL; // more clean. ...
} while (true);
}
function command()
{
$data = $this->splitcomm(); // This is an array, where each node is part of what SM sent to us :
// 0 => the command,
// and the others are arguments .. e.g. : user, server, password ...
if($this->myalive()) { // Check we can play with MySQL
if(strlen($data[0]) > 0 ) {
$this->logg("Command was : ".$data[0]);
}
switch($data[0]) {
case "isuser": // this is the "isuser" command, used to check for user existance
$this->jabber_user = $data[1];
$parms = $data[1]; // only for logging purpose
$return = $this->checkuser();
break;
case "auth": // check login, password
$this->jabber_user = $data[1];
$this->jabber_pass = $data[3];
$parms = $data[1].":".$data[2].":".md5($data[3]); // only for logging purpose
$return = $this->checkpass();
break;
case "setpass":
$return = false; // We do not want jabber to be able to change password
break;
default:
$this->stop(); // if it's not something known, we have to leave.
// never had a problem with this using ejabberd, but might lead to problem ?
break;
}
$return = ($return) ? 1 : 0;
if(strlen($data[0]) > 0 && strlen($parms) > 0) {
$this->logg("Command : ".$data[0].":".$parms." ==> ".$return." ");
}
return #pack("nn", 2, $return);
} else {
// $this->prevenir(); // Maybe useful to tell somewhere there's a problem ...
return #pack("nn", 2, 0); // it's so bad.
}
}
function checkpass()
{
/*
* Put here your code to check password
* $this->jabber_user
* $this->jabber_pass
* $this->jabber_server
*/
return true;
}
function checkuser()
{
/*
* Put here your code to check user
* $this->jabber_user
* $this->jabber_pass
* $this->jabber_server
*/
return true;
}
function splitcomm() // simply split command and arugments into an array.
{
return explode(":", $this->data);
}
function mysql() // "MySQL abstraction", this opens a permanent MySQL connection, and fill the ressource
{
$this->mysock = #mysql_pconnect($this->dbhost, $this->dbuser, $this->dbpass);
#mysql_select_db($this->dbbase, $this->mysock);
$this->logg("MySQL :: ". (is_resource($this->mysock) ? "Connecté" : "Déconnecté"));
}
function logg($message) // pretty simple, using syslog.
// some says it doesn't work ? perhaps, but AFAIR, it was working.
{
if($this->logging) {
#syslog(LOG_INFO, $message);
}
}
}
?>
when i start ejabberd live, i get this error in an infinite loop:
extauth script has exitted abruptly with reason 'normal'
External authentication script needs to be constantly running and thus must be a loop.
This is explained in ejabberd documentation:
https://www.ejabberd.im/files/doc/dev.html#htoc9
I suspect your script is exiting and not actually looping.
As a starting point, you should have a look at this project:
https://github.com/cburschka/ejabberd-auth-php

PHP - str_replace returns original string

I'm building a simple JS terminal shell emulator which posts its commands via AJAX to PHP.
Please leave security aside, this is only for learning and demo purposes.
Now my problem is, str_replace() won't work as expected, in fact, it returns the unchanged input string. It should work like this:
The name of this host is $hostname --> Yes, this string contains a variable --> Replace $hostname with testserver --> return The name of this host is testserver
What am I doing wrong?
This is my respond script for echo and export:
<?
// get environment variables from JSON
$vars = json_decode(file_get_contents('environment.json'), true);
// get request params
$method = $_SERVER['REQUEST_METHOD'];
$action = $_POST['action'];
$data = $_POST['data'];
switch ($action) {
case 'echo':
$cmd = $data;
// if the string in question contains a variable, eg. "the time is $time"
if (strpos($cmd,'$')) {
$output = '';
// for each environment variable as variable => value
foreach ($vars as $var => $val) {
// replace every variable in the string with its value in the command
$output = str_replace($var,$val,$cmd);
}
echo $output;
} else {
// if it does not contain a variable, answer back the query string
// ("echo " gets stripped off in JS)
echo $cmd;
}
break;
case 'export':
// separate a variable declaration by delimiter "="
$cmd = explode('=',$data);
// add a $-sign to the first word which will be our new variable
$var = '$' . array_shift($cmd);
// grab our variable value from the array
$val = array_shift($cmd);
// now append everything to the $vars-array and save it to the JSON-file
$vars[$var] = $val;
file_put_contents("environment.json",json_encode($vars));
break;
}
Better using :
if (strpos($cmd,'$') !== false) {
Then, every single replace will take the "first" data as its input data. You should proceed like this :
$output = $cmd;
// for each environment variable as variable => value
foreach ($vars as $var => $val) {
// replace every variable in the string with its value in the command
$output = str_replace($var, $val, $output);
}

Assigning a variable equal to Include function content

This issue came up to me in vBulletin system. i want to build a block in sidebar area to help me autmate some daily works.. i wrote php code like this :
<?php
$myDay = date('D');
$myHour = date('G');
// Saturday
if ($myDay == "Sat") {
if ($myHour >= 7) {
$output = include('textFilePath/saturday.txt');
} else {
$output = include('textFilePath/friday.txt');
}
}
// Sunday
if ($myDay == "Sun") {
if ($myHour >= 7) {
$output = include('textFilePath/sunday.txt');
} else {
$output = include('textFilePath/saturday.txt');
}
}
// and it goes on to friday...
// and in the end :
return $output;
?>
my problem is with include() function . when i return the $output value it returns a boolean(0 or 1) and include function writes out the txt files content in the beginning of document instead of "sidebar block"
i know i can echo the actual content instead of using include and txt files. but as i said i want to automate the daily tasks and give the users access to edit the txt files.
is there any other technique or function to assign the content of a local file to a variable ?
you may want to check
$output = file_get_contents('textFilePath/saturday.txt');
more information here : http://in3.php.net/file_get_contents

Categories