1

I am having an issue trying to get a php script to work for my website where I can add new items to my online store.

The code snippet I am having issues with is this:

$error = '';
$success = '';

if(isset($_POST['submit']))
{
    define("MAX_SIZE", "4096");

    $errors=0;

    $name = $_POST['name'];
    $price = $_POST['price'];
    $desc = filter_var($_POST['desc'], FILTER_SANITIZE_STRING);
    $image = $_FILES['image']['name'];
    $uploadedfile = $_FILES['image']['tmp_name'];

    if($image)
    {
        $filename = stripslashes($_FILES['image']['name']);
        $extension = getExtension($filename);
        $extension = strtolower($extension);
        if(($extension != "jpg") && ($extension != "jpeg") && ($extension != "png") && ($extension != "gif"))
        {
            $error .= '<p class="error">The file must be one of the following file types(jpg|jpeg|png|gif)</p>';
            $errors=1;
        }
        else
        {
            $size=filesize($_FILES['image']['tmp_name']);

            if($size > MAX_SIZE*1024)
            {
                $error .= '<p class="error">The file cannot exceed 4MB in size.</p>';
                $errors=1;
            }

            if($extension=="jpg" || $extension=="jpeg")
            {
                $uploadedfile = $_FILES['image']['tmp_name'];
                $src = imagecreatefromjpeg($uploadedfile);
            }
            else if($extension=="png")
            {
                $uploadedfile = $_FILES['image']['tmp_name'];
                $src = imagecreatefrompng($uploadedfile);
            }
            else
            {
                $src = imagecreatefromgif($uploadedfile);
            }

            list($width,$height)=getimagesize($uploadedfile);

            $newwidth=128;
            $newheight=128;
            $tmp=imagecreatetruecolor($newwidth,$newheight);

            imagecopyresampled($tmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);

            $filename = "../store/images/" . $_FILES['image']['name'];

            imagejpeg($tmp,$filename,100);

            $fname = $_FILES['image']['name'];

            imagedestroy($src);
            imagedestroy($tmp);
        }
    }

    if($name == '')
    {
        $error .= '<p class="error">You must enter a name for the product.</p>';
    }

    if(!preg_match('/^[a-zA-Z\s]+$/', $name))
    {
        $error .= '<p class="error">The product name can only contain letters and spaces.</p>';
    }

    if($_POST['type'] == 'KIT')
    {
        $type = 'KIT';
    }
    else if($_POST['type'] == 'VIP')
    {
        $type = 'VIP';
    }
    else if($_POST['type'] == 'OTHER')
    {
        $type = 'OTHER';
    }
    else
    {
        $error .= '<p class="error">You must select a valid type for the product.</p>';
    }

    if($price == '')
    {
        $error .= '<p class="error">You must enter a price for the product.</p>';
    }

    if(!preg_match('/^\d+(:?[.]\d{2})$/', $price))
    {
        $error .= '<p class="error">You must enter a valid price for the product.</p>';
    }

    if($desc == '')
    {
        $error .= '<p class="error">You must enter a description for the product.</p>';
    }

    $stmt = $db->prepare("SELECT * FROM products WHERE name = ?");
    if($stmt)
    {
        $stmt->bind_param('s',$name);
        $stmt->execute();

        if($stmt->num_rows > 0)
        {
            $error .= '<p class="error">This product already exists. Please choose a different name.</p>';
        }
    }
    else
    {
        $error .= '<p class="error">An error occurred at line 135. Please contact the site administrator.</p>';
    }

    if(empty($error) && !$errors)
    {
        $stmt = $db->prepare("INSERT INTO products (name, image, price, prod_desc, type) VALUES ( ?, ?, ?, ?, ? )");

        if($stmt)
        {
            $stmt->bind_param('sssss', $name, $fname, $price, $desc, $type);

            if($stmt->execute())
            {
                $success .= '<p class="success">Product added successfully.</p>';
            }
            else
            {
                $error .= '<p class="error">An error occured at line 158. Please contact the site administrator.</p>';
            }
        }
        else
        {
            $error .= '<p class="error">An error occured at line 154. Please contact the site administrator.</p>';
        }
    }
}

the section I am having an issue with is the if($stmt) block right after the if(empty($error) && !&errors) statement.

According to every syntax checker I've used for both the PHP itself, and the MySQL insert query, they all report no errors. But it keeps spitting out the error for line 154, and I can't figure out why. I've already verified the variables are being stored properly from the form by echoing them out, and I have also verified that the columns of the mysql table do exist, and are spelled correctly.

This is starting to drive me nuts, and when I tried to echo out the mysql error using $stmt->error or $db->error it came back blank, with no error whatsoever listed.

The only result I ever got was when I did mysqli_errno($db) which returned a 0.

Anyone know what is wrong with this code, or why it isn't working?

HTML Markup for the form:

<div id="form">
<form action="" method="post" enctype="multipart/form-data">
<table>
<th colspan="2">Add to Store</th>
<tr>
<td colspan="2">
<p>Please use the form below to add items to the store.</p>
<?php

if($error)
{
    echo $error;
}

if($success)
{
    echo $success;
}

?>
<hr>
<tr>
<td><label for="name">Product Name:</label></td>
<td><input type="text" name="name" id="name" value="<?php if(isset($name)) { echo $name; } else { echo ''; } ?>" /></td>
</tr>

<tr>
<td><label for="price">Product Price:</label></td>
<td><input type="text" name="price" id="price" size="6" maxlength="6" value="<?php if(isset($price)) { echo $price; } else { echo ''; } ?>" /></td>
</tr>

<tr>
<td><label for="image">Product Image:</label></td>
<td><input type="file" name="image" id="image" /><br /><small>File must be 128x128 pixels, and no larger than 4MB.</small></td>
</tr>

<tr>
<td><label for="type">Product Type:</label></td>
<td>
<select name="type">
<option value="VIP">VIP Package</option>
<option value="KIT">Donator Kit</option>
<option value="OTHER">Other</option>
</select>
</td>
</tr>

<tr>
<td colspan="2"><label for="desc">Product Description:</label></td>
</tr>
<tr>
<td colspan="2"><textarea name="desc" style="width: 500px; height:250px;"><?php if(isset($desc)) { echo $desc; } ?></textarea></td>
</tr>

<tr>
<td colspan="2"><input type="submit" name="submit" id="submit" value="Add Product" /></td>
</tr>

</table>
</form>
</div>
Bryan
  • 59
  • 1
  • 7
  • What error is it spitting out? What is line 154? – Jay Blanchard Jun 07 '16 at 14:59
  • Line 154 concerns the if($stmt) block directly after the following line at the bottom of the code: $stmt = $db->prepare("INSERT INTO products (name, image, price, prod_desc, type) VALUES ( ?, ?, ?, ?, ? )"); no error is being spit out, besides that message. – Bryan Jun 07 '16 at 15:02
  • Check your error logs for the *actual* error. There is something wrong with `$stmt` which indicates a problem with your query. – Jay Blanchard Jun 07 '16 at 15:03
  • I would have to contact my host for that, as I don't have access to the server logs. – Bryan Jun 07 '16 at 15:07
  • Add error reporting to the top of your file(s) right after your opening ` – Jay Blanchard Jun 07 '16 at 15:07
  • Ok, after adding those two lines, I got this at the top of the page: Notice: Use of undefined constant i - assumed 'i' in /usr/www/cgcserver/public/cgc/includes/functions.php on line 331 Warning: imagejpeg(../store/images/coal-ore.jpg): failed to open stream: No such file or directory in /usr/www/cgcserver/public/cgc/cpanel/AddShopItem.php on line 86 the function has this: function getExtension($str) { $i = strrpos($str,"."); if(!i) { return ""; } $l = strlen($str) - $i; $ext = substr($str,$i+1,$l); return $ext; } – Bryan Jun 07 '16 at 15:10
  • There you go - now you can track those issues down. Notice `if(!i)` is missing a `$` – Jay Blanchard Jun 07 '16 at 15:12
  • Ok, managed to eliminate the function issue (was missing a $ for the variable name). But for the file location, it keeps saying it can't find the filepath for the uploaded file. This page is located at root/cpanel/addproduct.php I need the image when uploaded to be sent to root/store/images I tried changing the filepath to /store/images, $_SERVER['DOCUMENT_ROOT'] . '/store/images/' and neither works for some reason. – Bryan Jun 07 '16 at 15:29
  • Make sure permissions allow access to the directories in question. – Jay Blanchard Jun 07 '16 at 15:34
  • Managed to fix that, but still getting the original error for line 154, and now no error message is being reported again. – Bryan Jun 07 '16 at 15:42
  • Are you connecting to the database before you try the query (I don't see that code here, so just asking)? Can you echo the statement error? – Jay Blanchard Jun 07 '16 at 15:45
  • There is no statement error being reported. The only time I can get any kind of error to print is when I do mysqli_errno($db) which prints errorcode 0, which I can't figure out what that is, it doesn't appear anywhere in the mysql or php manuals. As for the database connection, it is called in a separate file, and that file is called at the top of this problem page with a require call. All of my pages make this same call, and those pages work with sql queries. This is the only page I am having issues with. – Bryan Jun 07 '16 at 16:07
  • Can you share the markup for the form? – Jay Blanchard Jun 07 '16 at 16:15
  • edited original post to reflect the form markup. – Bryan Jun 07 '16 at 16:20
  • Unfortunately it has come to the point where we need to do one of two things; a.) get access to the error logs or, 2.) reduce the amount of code until to just the necessary bits, test and then work from there. There is nothing obvious to me in the markup or code causing the problem. – Jay Blanchard Jun 07 '16 at 16:25
  • Well, did a strip down, where I replaced all my html markup input fields with hidden fields with preset values, sent those to post, and ran the insert without any extra checks, and it inserted to the database with no issue. The issue is not with the query then, it is with one of the variables being passed into the query, but not sure which one. Thanks again for all the help given so far. – Bryan Jun 07 '16 at 16:48
  • You're welcome. I just wish there was more I could do to help. – Jay Blanchard Jun 07 '16 at 16:51
  • After MUCH breaking down of the code, I found the issue, but not sure why it is causing the issue. In the query above the problem query, where it selects all rows from the table where the name = the product name entered in post, it causes the second query to not go through at all. As soon as I commented it out, it all works. – Bryan Jun 07 '16 at 17:56
  • anyone searching for a tutorial on php mysqli,here you can find a detailed one. https://programmerblog.net/php-mysqli-tutorial-for-beginners/ – Maz I Aug 01 '17 at 06:13

2 Answers2

1

You never fetched any results, so num_rows will always be zero. There is a simple patch, use store_result():

$stmt->bind_param('s',$name);
$stmt->execute();
$stmt->store_result();

if($stmt->num_rows > 0)
{
    $error .= '<p class="error">This product already exists. Please choose a different name.</p>';
}

However, your code needs much more than that. You really should rewrite it and avoid nesting if statements so much. Use proper error reporting too.

Dharman
  • 30,962
  • 25
  • 85
  • 135
-1

So after much headache, I managed to find a workaround.

The source of the problem existed here:

$stmt = $db->prepare("SELECT * FROM products WHERE name = ?");
    if($stmt)
    {
        $stmt->bind_param('s',$name);
        $stmt->execute();

        if($stmt->num_rows > 0)
        {
            $error .= '<p class="error">This product already exists. Please choose a different name.</p>';
        }
    }
    else
    {
        $error .= '<p class="error">An error occurred at line 135. Please contact the site administrator.</p>';
    }

after changing this to the following:

$sql = "SELECT * FROM products WHERE name = '".$name."' LIMIT 1";
    $result = $db->query($sql);

    if(is_object($result) && $result->num_rows == 1)
    {
        $error .= '<p class="error">This product already exists. Please choose a different name.</p>';
    }

All is happy, and works without issue now. Still not sure why the original code didn't work, but it works now. Thanks for all the help.

Bryan
  • 59
  • 1
  • 7
  • Ditching the prepared statement made this work? That is really counter intuitive. – Jay Blanchard Jun 07 '16 at 18:16
  • yes it is, no idea why prepared statement didn't work, but the non-prepared did. – Bryan Jun 07 '16 at 18:21
  • Don't ditch prepared statements just becasue you had one simple mistake. All you had to do to patch this up was to call `store_result()` on your statement. – Dharman Mar 21 '20 at 15:37