I have a problem with php include section. In order to fully explain the problem, I created a test page for you.
First I want to show the schema of the files to you. Also you can download the test files from this LINK and you can test it online TEST LINK
As you can see, there is a subfolder in the htdocs (root) file and all php files in there. Now I'll show you the php code within the file, respectively.
appname/index.php
<?php include_once 'includes/config.php';?>
<div class="callPage">Click Here</div>
<div id="testBox"></div>
<script type="text/javascript">
$(document).ready(function(){
var siteurl = '<?php echo $url;?>';
$("body").on("click",".callPage", function(){
$.ajax({
url: siteurl+'content/test',
beforeSend: function() {
//Do something
},
complete:function(){
//Do something
},
success:function(response){
$("#testBox").html(response);
}
});
});
function LoadPage(){
$.get(siteurl+'content/test', function(data) {
$('#testBox').html(data);
});
}
LoadPage();
});
</script>
appname/content/test.php
<?php
include_once 'includes/config.php';
echo $text.'</br>';
echo $worked.'</br>';
?>
appname/includes/config.php
<?php
$url = 'http://localhost:8888/';
$text = 'Well Come! How are you today ?';
$worked = 'It is working :)';
?>
When you open the TEST LINK, LoadPage(); javascript function will call test.php in the content file and display it in #testBox. First you will not see anything in #testBox from index.php . Because config.php can not be included from test.php .
I know if I change this line include_once 'includes/config.php'; from test.php like this include_once '/appname/includes/config.php'; then problem will be fix.
But if the pages multiply and, I want to use the files in the root (htdocs or www) folder, I need to delete appname (subfolder name) => include_once 'appname/includes/config.php'; from all files. It will be a big problem when these files multiply.
Actually the question is exactly:
How can we include php files without specifying the full path to the include, when the application's path relative to the DOCUMENT_ROOT is variable or unknown and include_path cannot be reliably modified by all application users?
This is sometimes a problem with includes when you're not using the absolute path on the system.
Explanation
Depending on how PHP is running could affect the way include&require work, if PHP is running from inside the appname directory it will work fine if php is told it's running inside the appname directory via a connector it's fine. however, if PHP is run for example www-data#/usr/bin/# php /var/www/somesite.com/htdocs/appname/index.php the path can be broken.
Fix
if you use define("FS_ROOT", realpath(dirname(__FILE__))); as the first thing other than if ther is a namespace inside index.php you can then use include FS_ROOT."/includes/config.php"; this means file paths are used from the root of the system so it gets evaluated to include "/var/www/somesite.com/htdocs/appname/index.php"
Why this differs
This differs from ROOT_PATH as ROOT_PATH is sometimes set by PHP configuration by web hosts and this could be the problem. as the PHP execution path could be wrong casing the PHP host application to look in the wrong place for includes and requries.
This also means no include or require should ever be using ../ as you should know the path from your codebase.
your appname/index.php
<?php define("FS_ROOT", realpath(dirname(__FILE__)));
include_once FS_ROOT.'includes/config.php';?>
<div class="callPage">Click Here</div>
<div id="testBox"></div>
<script type="text/javascript">
$(document).ready(function(){
var siteurl = '<?php echo $url;?>';
$("body").on("click",".callPage", function(){
$.ajax({
url: siteurl+'content/test',
beforeSend: function() {
//Do something
},
complete:function(){
//Do something
},
success:function(response){
$("#testBox").html(response);
}
});
});
function LoadPage(){
$.get(siteurl+'content/test', function(data) {
$('#testBox').html(data);
});
}
LoadPage();
});
</script>
your appname/content/test.php
<?php
# as this file is loaded directly and is not in the root directory
# we apend the dirname result with ../ so realpath can resolve the root directory for this site
define("FS_ROOT", realpath(dirname(__FILE__)."../"));
include_once FS_ROOT.'includes/config.php';
echo $text.'</br>';
echo $worked.'</br>';
?>
Ideally, you should go through a bootstrap and .htaccess so you don't have to change redefine the FS_ROOT in every file loaded.
you can do this by making sure mod_rewrite is enabled in apache
create file .htaccess in appname folder
RewriteCond %{REQUEST_URI} \.(php)$
RewriteRule .* bootstap.php [L]
create bootstrap.php
define("FS_ROOT", realpath(dirname(__FILE__)));
include_once FS_ROOT.'includes/config.php';
if(file_exists(FS_ROOT.$_SERVER['REQUEST_URI']){
include(FS_ROOT.$_SERVER['REQUEST_URI']);
}else{
// 404
}
this means you don't require the include for the config as it's automaticly included before the script for that request is wanted this is just a base outline and is not secure (and could be easily exploited to reveal system files contents) I would highly recommend reading up on how to use MVC's and how they work it will give you a better understanding of loading files on demand and requiring files.
If the document file paths need to be dynamic you need to use a database. From what I understand you are planning to make the project bigger, and so you need a normalized database to minimize the amount of code written on the server and to keep your data consistent.
You need:
a parent table for filePaths
a parent table for fileNames
a parent table for akas <== This is because files may have same name in different folders
a parent table for folders
a mapping table to solve the akas-fileNames-filePaths-folders relationships.
I will show on an example from MySQLi.
With this code you create the tables in MySQL console or phpmyadmin:
// Create parent tables
create table `fileNames`
(
`fileName` VARCHAR(70) NOT NULL,
`description` VARCHAR(250) NULL,
PRIMARY KEY(`fileName`)
) ENGINE=InnoDB;
create table `fileAkas`
(
`aka` VARCHAR(100) NOT NULL,
`description` VARCHAR(250) NULL,
PRIMARY KEY(`aka`)
) ENGINE=InnoDB;
create table `filePaths`
(
`filePath` VARCHAR(250) NOT NULL,
`description` VARCHAR(250) NULL,
PRIMARY KEY(`filePath`)
) ENGINE=InnoDB;
create table `folderNames`
(
`folderName` VARCHAR(250) NOT NULL,
`description` VARCHAR(250) NULL,
PRIMARY KEY(`folderName`)
) ENGINE=InnoDB;
// Create mapping table
create table `fileNames_x_fileAkas_x_filePaths_x_folderNames`
(
`aka` VARCHAR(100) NOT NULL,
`fileName` VARCHAR(70) NOT NULL,
`filePath` VARCHAR(250) NOT NULL,
`folderName` VARCHAR(250) NOT NULL,
PRIMARY KEY (`aka`, `fileName`, `filePath`, `folderName`),
FOREIGN KEY (`aka`) REFERENCES `fileAkas` (`aka`) ON UPDATE CASCADE,
FOREIGN KEY (`fileName`) REFERENCES `fileNames` (`fileName`) ON UPDATE CASCADE,
FOREIGN KEY (`filePath`) REFERENCES `filePaths` (`filePath`) ON UPDATE CASCADE,
FOREIGN KEY (`folderName`) REFERENCES `folderNames` (`folderName`) ON UPDATE CASCADE
) ENGINE=InnoDB;
While this piece of code is only to make sure you are not making MyISAM tables because MyISAM doesn't have relationship constraints:
ENGINE=InnoDB
Now make a PHP program to easily add/change the data. Use this as a separate program and upload it to the server only when you need it:
<?php
// Database connection
$con = mysqli_connect("localhost","my_user","my_password","my_db");
// Function helper
function testIfAddedAndInsert($colName, $tableName, $value, $con)
{
$result = mysqli_query($con, "SELECT ".$colName." FROM ".$tableName." WHERE ".$colName."='".$value."'");
if(mysqli_num_rows($result) == 0)
mysqli_query($con, "INSERT INTO ".$tableName." (".$colName.") VALUES ('".$value."')");
}
// Call this to add new file
function addNewFile($name, $aka, $path, $folderName, $con)
{
testIfAddedAndInsert('fileName', 'fileNames', $name, $con);
testIfAddedAndInsert('fileAka', 'fileAkas', $aka, $con);
testIfAddedAndInsert('filePath', 'filePaths', $path, $con);
testIfAddedAndInsert('folderName', 'folderNames', $folderName, $con);
}
// Call this to change a file path
function changeFilePath($aka, $path, $con)
{
testIfAddedAndInsert('filePath', 'filePaths', $path, $con));
mysqli_query($con, "UPDATE `fileNames_x_fileAkas_x_filePaths_x_folderNames` SET `filePath`= '".$path."' WHERE `fileAka`='".$fileAka."' ");
}
// Call this to change all paths of all files that belong to a certain folder
function changeFolderPath($folderName, $path, $con)
{
testIfAddedAndInsert('folderPath', 'folderPaths', $folderPath, $con))
mysqli_query($con, "INSERT INTO `folderPaths` (`folderPath`) VALUES ('".$folderPath."')");
mysqli_query($con, "UPDATE `fileNames_x_fileAkas_x_filePaths_x_folderNames` SET `filePath`= '".$path."' WHERE `folderName`='".$folderName."' ");
}
// ...
// You can make as many different functions as you want
// To populate/change the database example:
addNewFile('config.php', 'conf_PHP_IndexPage', './../conf/', 'conf', $con);
// or change all the paths of the items in the folder (not counting subfolder items)
changeFolderPath('conf', './../../../', $con);
// You could use FOR loops with arrays to enter/change big chunks at a time
?>
Then, after populating your database with valid information, add this to every one of your main PHP files (the files that are including others):
<?php
// Database connection
$con = mysqli_connect("localhost","my_user","my_password","my_db");
// Function returns path of file from database
function returnPathToFile($fileAka, $con)
{
$result = mysqli_query($con, "SELECT fileName, filePath FROM fileNames_x_fileAkas_x_filePaths_x_folderNames WHERE fileAka='".$fileAka."'");
if(mysqli_num_rows($result) > 0)
{
$row = mysqli_fetch_array($result);
return $row[1].$row[0];
}
return '';
}
?>
And then just call the function to get the result:
<?php
$include = returnPathToFile('configFileForTheMainPage', $con);
include_once($include);
?>
If any changes occur to the file paths it is easy to change their values, while not having to ever even open the files ever again (for that purpose).
The ROOT_PATH definition is OK. You could include the path after the definition like:
include ROOT_PATH;
The Test.php is in content folder.
If you want to include config.php from includes folder, you must need to do it relatively, so you need to go one level upper.
include '../include/config.php';
This happening because you run the script standalone with ajax, and the folder structure is relative to the test.php.
Related
I am trying to build a simple web page where a user is prompt to click on an image as many times as desired. Eventually, after user is done s/he should click a link saying "I'm done" that should trigger the server to write to disk a sting (let's say: "I clicked x times", which I can manage to get).
I tried:
<a onclick="WriteNGo()" href="next_index.html">I am Done</a>
and of course:
function WriteNGo() {
$.ajax({
type: "POST",
url: 'php/save.php',
data: {writeMe: textToWrite}
});
}
where textToWrite is a global variable that contains the string. I can
alert(textToWrite)
it and get the required sentence.
and added php/save.php at the correct location:
<?php
$data = $_POST['writeMe'];
$f = "../d/data.txt";
file_put_contents($f,$data,FILE_APPEND);
?>
and did a
sudo chmod +777 d
on the folder.
I only want to end up with a text file containing my string, (i.e. "I clicked x times"). I am not even sure that the POST command triggers the PHP server.
One more thing: the index.html is in the root dir, where I am currently running:
php -S localhost:8000
So that there should have not been any problems.
I should also state that there was one time that the string was written, though I can't reproduce this it.
Not sure if this might address your problem. Maybe, try something like this to see, where your data might be written:
<?php
$data = $_POST['writeMe'];
$path = "../d";
$dir = $path . "/";
if (!is_dir($dir)) {mkdir($dir, 0755, true);}
// A faster alternative to file_put_content
$f = $dir . "/data.txt";
$fp = fopen($f, "x+");
fwrite($fp, $data);
fclose($fp);
?>
So today I have another small little issue with my PHP, that is causing me to get a server error. You see, I have this javascript function:
$.post('script.php', { limit: str }, function(result) {
console.log(result);
});
which of course makes a call to my php file:
require_once("../data/db-settings.php");
require_once("../data/file.php");
global $pdo;
$list = array();
$limit = $_POST["limit"];
chop($limit, ";");
$stmt = $pdo->prepare("SELECT cust_id, cust_addr FROM project WHERE " . $limit . " = cust_id");
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$list[] = $row;
}
echo $list;
The point of the php is to grab some information from a database that a user can dynamically change and use. The issue, I'm assuming, is with how I'm using PDO, because the code I'm using is in working order in another section. I also know that my function call is sending data and working properly, because when I check for just what I send, it sends properly.
Thanks for any help guys.
Check your query FROMproject can not be together.
Your query should look like this:
$pdo->prepare("SELECT cust_id, cust_addr FROM project WHERE " . $limit . " = cust_id");
It is an unobvious error!
So you step by step following the : http://pcsupport.about.com/od/findbyerrormessage/a/500servererror.htm
PDO doesn't throw Internal server error. Must be require_once.
checkout db-settings.php and file.php files. Require_once throws 500 error if it can't find files.
If the paths are correct, then check out included files.
proper way: check your log files.
I am not sure if this is the best way to do it, but I have a button that when pressed it call a onClick JS function and it passed two parameters. I want to save those two parameters on a php session, then load another page and use those values.
So, I know that if I use something like this on PAGE !:
<?php
session_start();
$message1 = "A message";
$message2 = "Another message";
$_SESSION['routineName'] = $message1;
$_SESSION['dayName'] = $message2;
?>
I can go to PAGE 2, and by using $_SESSION['routineName'] I can use that info.
So, on PAGE 1 I have that code inside the function that is called with my onClick:
function trackIt(routine, dayName)
{
<?php
session_start();
$message1 = "A message";
$message2 = "Another message";
$_SESSION['routineName'] = $message1;
$_SESSION['dayName'] = $message2;
?>
}
I tried things like:
function trackIt(routine, dayName)
{
<?php
session_start();
$_SESSION['routineName'] = ?> routine; <?php
$_SESSION['dayName'] = $message2;
?>
}
and others, but nothing works.
And this is how I am calling the onClick (trackIt) function:
echo('<td colspan="3" style="background-color:#005673; text-align:right; padding: 4px 0px;">
<button class="btnTrack" onClick="trackIt(\'' . $name . '\' , \'' . $nameday1 . '\')" >Track It!</button></td>');
What I want to do is to save both, routine and dayName, into the session.
Is it possible to save JS variables/parameters into PHP Session?
PS: I am using Wordpress.
Thanks!
The PHP code you put in your files is not executed at Javascript run time, it is executed even before the page gets sent to the client. So you can't access $_SESSION from anywhere within your content, you need to do that from Wordpress's code. Usually this is done via a plugin.
You need to pass your Javascript variables to a server side PHP. As #Grasshopper said, the best (or at least most maintainable way) is through AJAX:
// This is your JAVASCRIPT trackit function
function trackIt(routine, day) {
$.post(
'/wp-setvar.php',
{
routine : routine,
day : day
}, // You can add as many variables as you want (well, within reason)
function success(data) {
// Here we should receive, given the code below, an object
// such that data.result is a string saying "OK".
// Just in case you need to get back something from the server PHP.
// Otherwise just leave this function out.
}
);
};
On the server, you need to create a specific file to accept the incoming variables (it would be best if you did this from a plugin, in order not to add files outside the installation: such practices are frowned upon by security scanners such as WordFence). This here below is a butcher's solution.
<?php /** This is wp-setvar.php */
/** Set up WordPress environment, just in case */
require_once( dirname( __FILE__ ) . '/wp-load.php' );
session_id() || session_start();
nocache_headers();
// DO NOT, FOR ANY REASON, ACCESS DIRECTLY $_SESSION
// ONLY USE A VARIABLE WITHIN $_SESSION (here, "ajjx")
// OTHERWISE THIS MAY ALLOW ANYONE TO TAKE CONTROL OF YOUR INSTALLATION.
$_SESSION['ajjx'] = $_POST;
Header('Content-Type: application/json;charset=utf8');
die(json_encode(array(
'result' => 'OK', // This in case you want to return something to the caller
)));
Now whenever you need the session-saved variable, e.g. "routine", you put
<?php
...
$value = '';
if (array_key_exists('ajjx', $_SESSION)) {
if (array_key_exists('routine', $_SESSION['ajjx']) {
$value = $_SESSION['ajjx']['routine'];
}
}
Or you can define a function in your plugin,
function ajjx($varname, $default = '') {
if (array_key_exists('ajjx', $_SESSION)) {
if (array_key_exists($varname, $_SESSION['ajjx']) {
return $_SESSION['ajjx'][$varname];
}
}
return $default;
}
Then you just:
<?php print ajjx('routine', 'none!'); ?><!-- will print routine, or "none!" -->
or
<?php print ajjx('routine'); ?><!-- will print nothing if routine isn't defined -->
An even more butcherful solution is to add the function definition above within wp-config.php itself. Then it will be available everywhere in Wordpress. Provided you have access to wp-config.php. Also, backup wp-config first and use a full FTP client to do it; do not use a Wordpress plugin to edit it, since if wp-config crashes, the plugin may crash too... and you'll find yourself in a my-can-opener-is-locked-within-a-can situation.
If you don't feel comfortable with some of the above, it's best if you do nothing. Or practice first on an expendable Wordpress installation that you can reinstall easily.
I am creating a website that has users log in and select a pdf document that they want to download. When they open up the document to view and possibly download, I want data to be logged into a database at the same time.
The code to send the data to the database works (Except for: Undefined index: learningMaterial). But when I want to have the pdf document open and at the same time log the user and other data, all that happens is the document opens up.
Any advice would be appreciated, even for overall better methods of going about what I'm trying to achieve here. Still inexperienced with PHP.
See code below.
HTML
<form name="myform" method='post' action="../includes/writeStats.php">
<input type='hidden' name='learningMaterial' id='learningMaterial' value='learningMaterial'>
<a href='../documents/test.pdf' id='mylink' class='courses' name='Driver Training'> Driver Training </a>
</form>
JS - In header
<script type="text/javascript">
function submitform(){
document.myform.submit(); }
var form = document.getElementById("myform");
document.getElementById("mylink").addEventListener("click", function () {
submitform();
});
</script>
PHP
<?php
$con=mysqli_connect("localhost","root","password","qmptest");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
//Get latest log nr
$result = mysqli_query($con,"SELECT * FROM logbook ORDER BY log DESC LIMIT 1");
while($row = mysqli_fetch_array($result)) {
$log = $row['log'] + 1;
//If statement to check if log is 0(first entry) to go here
}
$date = date("Y/m/d");
session_start(); // Start a new session
$person = $_SESSION['currentUser'];
//Not sure if this is correct along with my HTML input
$material = mysqli_real_escape_string($con, $_POST['learningMaterial']);
//Insert into database
$sql="INSERT INTO logbook (log, date, person, learningMaterial)
VALUES ('$log', '$date', '$person', '$material')";
if (!mysqli_query($con,$sql)) {
die('Error: ' . mysqli_error($con));
}
mysqli_close($con);
?>
Your way, clicking the link will override the form being submitted. This leads to the file opening and the form never going through.
Instead, you could try either opening the file in a new window by adding target="_blank" to the tag, or send the files URL through to the PHP, executing the database code then adding to the end:
header("Location: http://yourdomain.com/yourfile.pdf");
Your file is just a normal file being returned by your web server:
<a href='../documents/test.pdf' ...
So while you may be able to suggest to users or browsers that they should invoke some code before downloading this file, you can't actually require it. Any user can just request the file directly. And since PDF files don't execute PHP code (thankfully), your server-side PHP code has no way of knowing that the file has been requested.
What you can do is obscure the file itself behind a PHP request. You can create something like a download.php page which accepts the name of a file (test.pdf) and returns that file.
Be very careful when doing this. Don't just allow users to request any file and blindly return whatever they request. A user can request something like "../../../../../../../../../../etc/passwd" and if your code just builds a path and returns the file then you've just given users a sensitive file. It's best practice to keep a finite known list of identified files (perhaps in a database table) and let users request by the identifier rather than by the file path itself. That way the actual path is only ever known server-side in data that you control.
The main point here, however, is that by using such a page you inject some PHP code in between the user and the file. In order to get the file, the user needs to make a request to a PHP page. On that page you can record the act of the user having requested the file. (As well as perform authorization checks to validate that the user is allowed to view the file, etc.)
Never assume client-side code is going to do what you expect it to do. If you want to ensure something happens for anything approaching security or auditing purposes, it needs to happen in server-side code.
I used this in my index.php
<?
include('config.php');
if($site->maintenance > 0){
echo "<script>document.location.href='maintenance'</script>";
exit;
}
?>
and in my config.php after checked database connection
$site = mysql_fetch_object(mysql_query("SELECT * FROM problems"));
I made a table in my database and called it problems but even when I put the value 0, it transfers me to maintenance. When I checked the variable $site by var_dump($site) it outputs:
bool(false)
and if I checked it like this: var_dump($site->maintenance) it outputs:
NULL
What do I have to do to manage the maintenance from database and when I want my site to work I change value?
Why you are using JS for this? What if user JS is off? I would use PHP instead
Create a table for maintenance with a column say maintenance_status, now this will hold a boolean value, 0 1... 0 => off, 1 => on, will keep only a single record which will be created once, and later will update it always...
So now later you create this function
function check_maintenance($connection) { /* Call this function on every page,
pass your database connection var
as a function parameter */
$query = mysqli_fetch_array(mysqli_query($connection, "SELECT * FROM tbl_maintenance LIMIT 1"));
/* Limit 1 is optional if you are using only 1 row as I told you,
if you are keeping records of the previous maintenance, probably
you've to sort desc and use limit 1 */
if($query['tbl_maintenance'] == '1') { //Check boolean value, if it's on than redirect
header('Location: maintenance.php'); //Redirect the user to maintenance page
exit;
}
}
The fact that $site is false, could being caused by problem with the query. Change the mysql code to:
$result = mysql_query("SELECT * FROM problems");
if(!$result) {
die(mysql_error();
}
$site = mysql_fetch_object($result);
Further you should learn howto enable error messages in PHP. I guess there are bunch of them. They are disabled by default as it could be a security risk in a production system. But when you are developing you MUST enable them. You can enable it in the php.ini of development system:
php.ini:
...
display_errors=1
...
log_errors=1
...
error_log="/path/to/writable/file"
...
error_reporting=E_ALL
After modifying the php.ini don't forget to restart the web server.