Undefined Variable Error Thrown When Using A $_GET Request - php

I have a page that connects to a MySQL database via PHP. On this page the data is fetched to load an image and its related details. This page all work OK when the page is loaded.
I also have a module included on this page where users can create a board (which will hold images) along a certain theme.
On other pages this board module works OK, but on a page where a $_GET request happens, which is needed to identify a user's username or an image filename (depending on the page), the board module doesn't work correctly. When you create a new board it fails and I get a PHP error saying Undefined variable: filename in with reference to the line of code ':filename' => $filename in the execute function below.
When this boards module is used to create a new board name I have some JavaScript fetch() code on the page that prevents a hard refresh. I'm not sure if this is causing the problem (although this JS is also used on the pages that don't have a problem, i.e. no $_GET request). On pages where this is no $_GET request everything works as expected.
Note: in the code below $connection is the database connection from a db.php file
PHP on pageload that loads the image and related data
isset($_GET['filename']) ? $filename = $_GET['filename'] : header("Location: login.php");
$image_stmt = $connection->prepare("SELECT * FROM `lj_imageposts` WHERE `filename` = :filename");
$image_stmt -> execute([
':filename' => $filename // variable that returns the error
]);
$image_row = $image_stmt->fetch();
// if the GET url parameter doesn't exist/changed
if ($image_row == 0) { header ("Location: index.php"); exit; }
$db_userid = htmlspecialchars($image_row['user_id']);
$db_image_id = htmlspecialchars($image_row['image_id']);
$db_image_title = htmlspecialchars($image_row['image_title']);
$db_image_filename = htmlspecialchars($image_row['filename']);
$db_image_ext = htmlspecialchars($image_row['file_extension']);
$db_username = htmlspecialchars($image_row['username']);
?>
---- HTML OUTPUT THAT INCORPORATES THE ABOVE VARIABLES
PHP for the boards module
if (isset($_POST['submit-board-name'])) {
$create_board_name = $_POST['create-board-name'];
if(strlen(trim($create_board_name)) < 10) {
$error[] = "Board name must be at least 10 characters long";
}
if(strlen(trim($create_board_name)) > 150) {
$error[] = "Board name can be at less than 150 characters long";
}
if(!isset($error)) {
try {
$createBoardSQL = "INSERT INTO lj_boards (board_name, user_id) VALUES (:board_name, :user_id )";
$bstmt = $connection->prepare($createBoardSQL);
$bstmt->execute([
':board_name' => $create_board_name,
':user_id' => $db_id
]);
} catch(PDOException $e) {
echo "Error: " . $e->getMessage();
}
}
} else {
// give values an empty string to avoid an error being thrown before form submission if empty
$create_board_name = "";
}

This first line is unnecessarily cryptic, making the mistake harder to spot (and harder to fix):
isset($_GET['filename']) ? $filename = $_GET['filename'] : header("Location: login.php");
It's pretending to be an expression, but it's actually an if statement in disguise - it consists of nothing but side effects. Let's write it out more clearly:
if ( isset($_GET['filename']) ) {
$filename = $_GET['filename'];
}
else {
header("Location: login.php");
}
Now we can look more clearly at what each branch does:
The if branch sets a variable. If the code takes that branch, everything should be fine.
The else branch sets a header to be included when PHP sends the response. It doesn't do anything else, and it doesn't set the variable, so if this path is taken, you'll have a problem later.
What you probably intended to happen was for the else branch to set that header and then immediately stop processing. For that you need an exit; statement (also known as die;
if ( isset($_GET['filename']) ) {
$filename = $_GET['filename'];
}
else {
header("Location: login.php");
exit;
}

Related

PHP file upload error conditions

I am trying to create a profile editing setup. It seems as though the information is edited only when an image is being uploaded. I found out that allowing the error message to be a condition allows for some more manipulation so I attempted it now my condition statement is not working as it should.
if($_FILES['files']['error']==0) {
print_r($_FILES['files']['error']);
echo "if";
foreach($_FILES['files']['name'] as $file => $name) {
$filename = $name;
try{
if(move_uploaded_file($_FILES['files']['tmp_name'][$file],'uploads/'.$filename)) {
$updateInfo = $db->prepare("UPDATE users SET image = :image, aboutme = :aboutme WHERE id = :id");
$updateInfo->bindParam(":image", $filename);
$updateInfo->bindParam(":id", $_SESSION['user']['id']);
$updateInfo->bindParam(':aboutme', $aboutme);
$updateInfo->execute();
}
} catch(Exception $e) {
echo $e;
}
}
} elseif($_FILES['files']['error'] == 4) {
print_r($_FILES['files']['error']);
echo "Elseif";
try{
$updateInfo = $db->prepare("
UPDATE users
SET
aboutme = :aboutme
WHERE id = :id
");
$updateInfo->bindParam(':id', $_SESSION['user']['id']);
$updateInfo->bindParam(':aboutme', $aboutme);
$updateInfo->execute();
} catch(Exception $e) {
echo $e;
}
} else{
print_r($_FILES['files']['error']);
echo "else";
}
}
When I check what array is being sent, its the correct one but the wrong condition, ie: it would run the else statement no matter the file check.
My question:
Is there something wrong with my code, with the exception of any security or efficiency flaws?
$_FILES['files']['error'] returns error code along with the file array. There are different type of error codes, all codes are mentioned in following link with details:
Please check by
print_r($_FILES['files'])
and see what are you getting in response.
As you posted your array response, you can get error code by $_FILES['files']['error'][0] or use switch case as mentioned in following link.
See here for more details:
http://php.net/manual/en/features.file-upload.errors.php
Also regarding debugging, always debug code step by step from top to bottom. Check $_POST, $_FILES, $_SERVER etc details if you get some problem particular related to data process.

Errors in php script apparently all coming from one line of code

I'm having trouble with a PHP script which apparently is getting errors from one single line. The top line in this bit of code is apparently causing quite a bit of trouble:
if (move_uploaded_file($_FILES["image"]["tmp_name"], "./upload/".$imageName)) {
mysql_query("INSERT " .$pages. " SET inmenu='$inmenu', pagid='$pagid', title='$titlename', content='$contentname', image='$image', youtube='$youtube'")
or die(mysql_error());
header("Location: index.php");
}
The errors I'm getting for the top line of code:
Warning: Unexpected character in input: ' in cms/new.php on line 131
Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at cms/new.php:131) in cms/new.php on line 85
First I thought CHmodding the upload folder to 777 would solve this error, but apparently it doesn't. I really don't know what to do anymore. Is there anyone who can help?
The complete block of code that includes the little snippet above:
<?php
}
session_start();
if(!isset($_SESSION['username'])){
header("location:login.php");
}
include("config.php");
// check if the form has been submitted. If it has, start to process the form and save it to the database
if (isset($_POST['submit']))
{
//set root
$root = getcwd ();
// get form data, making sure it is valid
$inmenu = mysql_real_escape_string(htmlspecialchars($_POST['inmenu']));
$pagid = strtolower(str_replace(" ", "-", mysql_real_escape_string(htmlspecialchars($_POST['pagid']))));
$titlename = mysql_real_escape_string(htmlspecialchars($_POST['title']));
$contentname = mysql_real_escape_string(htmlspecialchars($_POST['contentedit']));
$youtube = mysql_real_escape_string(htmlspecialchars($_POST['youtube']));
// check to make sure both fields are entered
if ($titlename == '' || $pagid == '')
{
// generate error message
$error = 'ERROR: Please fill in all required fields!';
// if either field is blank, display the form again
renderForm($pagid, $titlename, $contentname, $error);
}
else
{
if(file_exists($root."/upload/".$_FILES["image"]["name"]))
{
$filename = explode(".",$_FILES['image']['name']);
$randomnumber = rand(0, 10000);
$imageName = $filename[0].$randomnumber.".".$filename[1];
}
else
{
$imageName = $_FILES['image']['name'];
}
$image = mysql_real_escape_string(htmlspecialchars("/upload/".$imageName));
if (move_uploaded_file($_FILES["image"]["tmp_name"], "./upload/".$imageName)) {
// save the data to the database
mysql_query("INSERT " .$pages. " SET inmenu='$inmenu', pagid='$pagid', title='$titlename', content='$contentname', image='$image', youtube='$youtube'")
or die(mysql_error());
// once saved, redirect back to the view page
header("Location: index.php");
}
else {
// save the data to the database
mysql_query("INSERT " .$pages. " SET inmenu='$inmenu', pagid='$pagid', title='$titlename', content='$contentname', youtube='$youtube'")
or die(mysql_error());
// once saved, redirect back to the view page
header("Location: index.php");
}
}
}
else
// if the form hasn't been submitted, display the form
{
renderForm('','','');
}
?>
When using double quotes you can just insert PHP variables so
Try this:
if (move_uploaded_file($_FILES["image"]["tmp_name"], "./upload/".$imageName)) {
$query = "INSERT " . $pages . SET inmenu=$inmenu, pagid=$pagid, title=$titlename, contenct=$contentname, image=$image, youtube=$youtube";
mysql_query($query) or die(mysql_error());
header("Location: index.php");
}
Another way (if you'd like) would be this:
if (move_uploaded_file($_FILES["image"]["tmp_name"], "./upload/".$imageName)) {
mysql_query("INSERT " .$pages. " SET inmenu='".$inmenu."', pagid='".$pagid."', title='".$titlename."', content='".$contentname."', image='".$image."', youtube='".$youtube."'")
or die(mysql_error());
header("Location: index.php");
}

PHP display error on another page

I'm having issues to send an occuring error to another page.
I have already created the page the error will be sent to, and I've tried a header function. But that doesn't seem to work. Here is the php code that I am using for the page.
<?php
if(isset($_POST['username'], $_POST['password'])){
//login the user here
$connect = mysql_connect("","","")or die(mysql_error());
mysql_select_db("")or die(mysql_error());
$errors = array();
$username = strip_tags(mysql_real_escape_string($_POST['username']));
$password = strip_tags(mysql_real_escape_string($_POST['password']));
if (empty($Regi_Username) || empty($Regi_password)) {
$errors[] = 'All fields are requerid';
} else {
if (strlen($Regi_Username) > 25) {
$errors[] = 'Username is to long';
}
if (strlen($password) > 25) {
$errors[] = 'Password is to long';
}
}
$password = md5($_POST['password']);
$loginquery = "SELECT * FROM regi WHERE username='$username' and password='$password'" or die(mysql_error());
$result = mysql_query($loginquery);
$count = mysql_num_rows($result);
mysql_close();
if($count==1){
$seconds = 2000 + time();
setcookie(loggedin, date("F jS - g:i a"), $seconds);
header("location:member.php");
} else {
echo 'Wrong username and password please try agian.';
}
}
?>
Pass the GET variable in your URL like..
header('Location:page.php?err=1');
exit;
On the other page use this
if(isset($_GET['err'] && $_GET['err'] == 1) {
echo 'Error Occured';
}
Here is a session based approach. This is the best way to pass messages from one page to another as they are stored in the user's session (a piece of data related to each user and stored in the server side) and not in the browser (like cookies or URL GET parameters, which can be easily corrupted), so it is really quite harder to manipulate the messages from 3rd parties.
Page process.php:
<?php
// Very top of your page
session_start();
$_SESSION['errors'] = array();
// Do stuff now...
// ...
// Hey it's a X error!
$_SESSION['errors']['X'] = 'Message for X error';
// Continue doing stuff...
// ...
// OMG! It's a Y error now!
$_SESSION['errors']['Y'] = 'Message for Y error';
// Keep doing stuff till you're done...
// All right, process is finished. Any Errors?
if (count($_SESSION['errors']) > 0) {
// It seems there's been any errors
// time to redirect to error-displaying page
header('Location: error-page.php');
exit;
}
Page error-page.php:
<?php
// Very top of your page
session_start();
// Let's check if there is any error stored in the session.
// In the case no errors found, it is better to redirect to another page...
// ...why anybody would end in this page if no errors were thrown?
if (!isset($_SESSION['errors']) || !is_array($_SESSION['errors']) || empty($_SESSION['errors'])) {
header('Location: home.php');
exit;
}
// If we reach this point it means there's at least an error
foreach ($_SESSION['errors'] as $errorCode => $errorMessage) {
// Here we can display the errors...
echo '<p>Error ', $errorCode, ': ', $errorMessage, '</p>', PHP_EOL;
}
// You can also do stuff only if a certain error is received
if (array_key_exists('X', $_SESSION['errors'])) {
// Error `X` was thrown
echo '<p>Oh no! It seems you suffered a X error!!</p>', PHP_EOL;
echo 'Click here to go back home.', PHP_EOL;
}
// At the end you should to remove errors from the session
$_SESSION['errors'] = array();
// or
unset($_SESSION['errors']);
You could use Alien's method, but it'd better if you use Session:
// Assume you init the session already; Use json_encode since you use array for $errors
$_SESSION['errors_msg'] = json_encode($errors);
header("location:member.php");
// Remember to exit here after we call header-redirect
exit;
Besides, there are a lot of problems is your currently code:
Use salt for hashing password
Use mysqli over mysql
Filtering input, escaping output
.. Read other recommendations here in this topic ..
Please read http://www.phptherightway.com/. There is a lot of right recommendation (of course not all) for PHP.

PHP session variable, check then delete

Code:
if(!$picture) $error = $error."<div>This is a photo site, we require you select a photo.</div>";
if(!$imgname) $error = $error."<div>You must enter a name for your photo.</div>";
if(!$description) $error = $error."<div>You must enter a description for your photo.</div>";
else if(strlen($description) > 500) $error = $error."<div>Your descriptions to long. 500 characters max.</div>";
if(!$error) {
$case = 2;
$max_width_new = 190;
$make_thumb=1; $make_medium=1; $make_original=1;
$imagename = "picture";
$folders = "accounts/".$dbid."/";
if(!file_exists($folders))
mkdir($folders);
include("scripts/php/uploadpicture.php");
if($file) {
$connect = mysql_connect("localhost","headinth_admin","adobe1234");
mysql_select_db("headinth_core");
mysql_query("INSERT INTO pictures (id, uploader, name, description, location, picture, date) VALUES('','$dbid','$imgname','$description','$location','$file_name','$date')");
$_SESSION['uploaded'] = 1;
header("location: ?upload");
}
} else echo "<div class='green f18 fl coolvetica' style='text-align:left;'>".$error."</div><div class='c20'></div>";
}
if(isset($_SESSION['uploaded'])) {
echo "<div class='white f18 fl coolvetica' style='text-align:left;'>Your picture was uploaded.</div><div class='c20'></div>";
unset($_SESSION['uploaded']);
}
?>
So it goes through and if everything successful it declares $_SESSION['uploaded'] = 1. Makes sense. Since theres a header it refreshes the page. Then I check if $_SESSION['uploaded'] exists, to see if a photo was just uploaded. If it was then it should send the message "Your photos been uploaded". Then it would have to delete the $_SESSION['uploaded'] variable so it doesn't show up again if the page is refreshed or an invalid submission is made.
The issue is that its just skipping the if(isset($_SESSION['uploaded'])) line and just unsetting the session. So its not echoing the success message. IF i delete the unset it works, just always appears until the entire session is destroyed. So the goal, carry a variable over a page refresh, echo it then remove it.
header() doesn't halt execution of your script. After the header() command, the script continues to your isset()/unset() block. The solution is to die after the header():
header("location: ?upload");
die;
I think its just an issue with the order that you're doing the output and the unsetting.
$_SESSION['test'] = 1;
echo "test session variable is: {$_SESSION['test']} <br />";
unset($_SESSION['test']);
echo "test session variable is: {$_SESSION['test']}";
will output:
test session variable is: 1
test session variable is:

Having trouble getting the right idea

well i'm writing a php code to edit tags and data inside those tags but i'm having big trouble getting my head around the thing.
basically i have an xml file similar to this but bigger
<users>
<user1>
<password></password>
</user1>
</users>
and the php code i'm using to try and change the user1 tag is this
function mod_user() {
// Get global Variables
global $access_level;
// Pull the data from the form
$entered_new_username = $_POST['mod_user_new_username'];
$entered_pass = $_POST['mod_user_new_password'];
$entered_confirm_pass = $_POST['mod_user_confirm_new_password'];
$entered_new_roll = $_POST['mod_user_new_roll'];
$entered_new_access_level = $_POST['mod_user_new_access_level'];
// Grab the old username from the last page as well so we know who we are looking for
$current_username = $_POST['mod_user_old_username'];
// !!-------- First thing is first. we need to run checks to make sure that this operation can be completed ----------------!!
// Check to see if the user exist. we just use the normal phaser since we are only reading and it's much easier to make loop through
$xml = simplexml_load_file('../users/users.xml');
// read the xml file find the user to be modified
foreach ($xml->children() as $xml_user_get)
{
$xml_user = ($xml_user_get->getName());
if ($xml_user == $entered_new_username){
// Set array to send data back
//$a = array ("error"=>103, "entered_user"=>$new_user, "entered_roll"=>$new_roll, "entered_access"=>$new_access_level);
// Add to session to be sent back to other page
// $_SESSION['add_error'] = $a;
die("Username Already exist - Pass");
// header('location: ../admin.php?page=usermanage&task=adduser');
}
}
// Check the passwords and make sure they match
if ($entered_pass == $entered_confirm_pass) {
// Encrypt the new password and unset the old password variables so they don't stay in memory un-encrytped
$new_password = hash('sha512', $entered_pass);
unset ($entered_pass, $entered_confirm_pass, $_POST['mod_user_new_password'], $_POST['mod_user_confirm_pass']);
}
else {
die("passwords did not match - Pass");
}
if ($entered_new_access_level != "") {
if ($entered_new_access_level < $access_level){
die("Access level is not sufficiant to grant access - Pass");
}
}
// Now to load up the xml file and commit changes.
$doc = new DOMDocument;
$doc->formatOutput = true;
$doc->perserveWhiteSpace = false;
$doc->load('../users/users.xml');
$old_user = $doc->getElementsByTagName('users')->item(0)->getElementsByTagName($current_username)->item(0);
// For initial debugging - to be deleted
if ($old_user == $current_username)
echo "old username found and matches";
// Check the variables to see if there is something to change in the data.
if ($entered_new_username != "") {
$xml_old_user = $doc->getElementsByTagName('users')->item(0)->getElementsByTagName($current_username)->item(0)->replaceChild($entered_new_username, $old_user);
echo "Username is now: " . $current_username;
}
if ($new_pass != "") {
$current_password = $doc->getElementsByTagName($current_user)->item(0)->getElementsByTagName('password')->item(0)->nodeValue;
//$replace_password = $doc
}
}
when run with just the username entered for change i get this error
Catchable fatal error: Argument 1 passed to DOMNode::replaceChild() must be an instance of DOMNode, string given, called in E:\xampp\htdocs\CGS-Intranet\admin\html\useraction.php on line 252 and defined in E:\xampp\htdocs\CGS-Intranet\admin\html\useraction.php on line 201
could someone explain to me how to do this or show me how they'd do it.. it might make a little sense to me to see how it's done :s
thanks
$entered_new_username is a string so you'll need to wrap it with a DOM object, via something like$doc->createElement()
$xml_old_user = $doc->getElementsByTagName('users')->item(0)->getElementsByTagName($current_username)->item(0)->replaceChild($doc->createElement($entered_new_username), $old_user);
This may not be quite right, but hopefully it points you in the correct direction.
alright got it writing and replacing the node that i want but i have ran into other issues i have to work out (IE: it's replacing the whole tree rather then just changing the node name)
anyway the code i used is
// For initial debugging - to be deleted
if ($old_user == $current_username)
echo "old username found and matches";
// Check the variables to see if there is something to change in the data.
if ($entered_new_username != "") {
try {
$new_node_name = $doc->createElement($entered_new_username);
$old_user->parentNode->replaceChild($new_node_name, $old_user);
}
catch (DOMException $e) {
echo $e;
}
echo "Username is now: " . $current_username;
}
if ($new_pass != "") {
$current_password = $doc->getElementsByTagName($current_user)->item(0)->getElementsByTagName('password')->item(0)->nodeValue;
//$replace_password = $doc
}
$doc->save('../users/users.xml');

Categories