LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Question about an unexpected T_VARIABLE (http://www.linuxquestions.org/questions/programming-9/question-about-an-unexpected-t_variable-4175413290/)

errigour 06-25-2012 11:39 AM

Question about an unexpected T_VARIABLE
 
How come the code below gives me the error below?

Code snippet:
Code:

    $filename = $_FILES["file"]["name"]
    $ext = substr(strrchr($filename, '.'), 1);

Error message:
Code:

Parse error: syntax error, unexpected T_VARIABLE in ************** on line 43

Kustom42 06-25-2012 11:48 AM

Remove the dollar sign infront of the variable you are trying to declare. You do not add a dollar sign when you are declaring a variable, only when you are calling upon it.

michaelk 06-25-2012 12:20 PM

What is posted is the proper PHP syntax.
It might just be a typo but you are missing a ; on the first line posted.

Kustom42 06-25-2012 12:23 PM

Didn't notice it was PHP first time through, just saw the dollar signs and assumed BASH. My first post is incorrect for PHP, thanks for catching it michaelk

errigour 06-25-2012 11:10 PM

Ok I added a semicolon and it still gives me this error.

Code:

Notice: Undefined index: file in C:\Apache2.2\htdocs\Post Picture\Upload File.php on line 42 Home PageFile is not a recognized extension

line 42 is:
$filename = $_FILES["file"]["name"];


michaelk 06-26-2012 04:52 AM

Without seeing your code I can only guess.
Does your form match your PHP code i.e. something like
Quote:

Choose a file to upload: <input name="file" type="file" />

Nominal Animal 06-26-2012 05:53 AM

Quote:

Originally Posted by errigour (Post 4711925)
Ok I added a semicolon and it still gives me this error.

Code:

Notice: Undefined index: file in C:\Apache2.2\htdocs\Post Picture\Upload File.php on line 42

That is not an error, it is just a notice. It means there was no "file" entry in the $_FILES array. That happens when you don't supply a file to be uploaded, or do a GET query to the script instead of a POST one. You can suppress the notice by using
Code:

$filename = @$_FILES["file"]["name"];
but then $filename === NULL if there was no uploaded file.

I hope I'm not offending you, but perhaps it would be worth your while to read some PHP tutorials first? Many are poor in quality -- I haven't found one I'd be comfortable with --, so I'm afraid you'll have to rely on a number of sources simultaneously. For example, I'd rather not have to explain here why there are three consecutive equals signs in the statement above: it is a very basic, core PHP operator you should be comfortable with.

errigour 06-26-2012 06:14 AM

Well the reason I asked is because there wasn't a null file sent. That line doesn't work even if there is a file present using the post method. Ill post the code if you want but it only messes up when I substr that string.

---------- Post added 06-26-12 at 07:15 AM ----------

Code:

<?php
function foldersize($path) {

    $total_size = 0;
    $files = scandir($path);


    foreach($files as $t) {

        if (is_dir(rtrim($path, '/') . '/' . $t)) {

            if ($t<>"." && $t<>"..") {

                $size = foldersize(rtrim($path, '/') . '/' . $t);

                $total_size += $size;
            }
        } else {

            $size = filesize(rtrim($path, '/') . '/' . $t);

            $total_size += $size;
        }
    }

    return $total_size;
}

if($_FILES["file"]["error"] > 0)
{
    if($_FILES["file"]["error"] = 4)
    {
        echo "Non existing file recieved<br>";
        include('index.html');
        exit;
    }
    echo "Error: " . $_FILES["file"]["error"] . "<br>";
}
else
{
    $size = foldersize("Temporary Internet Files/");

    if ($size >= 500000)
    {
        echo "<a href=\"../\">Home Page</a>";
        echo "File size on disk has exceeded<BR>\n";
        exit;
    }
    if($_FILES["file"]["size"] > 570000)
    {
        echo "File size exceeds 5.4 Megabytes<br>";
        include('index.html');
        exit;
    }
    if(file_exists("Temporary Internet Files" . $_FILES["file"]["name"]))
    {
        echo $_FILES["file"]["name"] . " already exists. <BR>";
        include('index.html');
        exit;
    }
    else
    {
        move_uploaded_file($_FILES["file"]["tmp_name"], "Temporary Internet Files/" . $_FILES['file']['name']);
        echo "Upload  : " . ($_FILES["file"]["name"]) . "<br>\n";
        echo "Type    : " . ($_FILES["file"]["type"]) . "<br>\n";
        echo "Size    : " . ($_FILES["file"]["size"] / 1024) . " Kb<br>\n";
        echo "TMP File : " . $_FILES["file"]["tmp_name"] . "<br>\n";
        echo "Stored In: " . "Temporary Internet Files/" . $_FILES["file"]["name"] . "<BR>\n";
        echo "<BR><BR><BR><BR>\n";
        echo "<img src=\"Temporary Internet Files/" . $_FILES["file"]["name"] . "\"><BR>\n";
    }
}
?>


Nominal Animal 06-26-2012 07:50 AM

Quote:

Originally Posted by errigour (Post 4712344)
Well the reason I asked is because there wasn't a null file sent.

Null file?

The PHP page can be reached in multiple ways.

POST upload only occurs if the page is reached due to a <form method="POST" action="URL-to-PHP-page" ... (or equivalent Javascript, or equivalent request in any programming language). A normal request, a GET request, occurs when the PHP page is reached via a simple link, for example when the user simply types out the URL to the PHP page.

For GET requests, both $_POST and $_FILES arrays will be empty or NULL. If the user does not pick a file to be uploaded, or the foo in <input type="file" name="foo" ... in the upload form does not match, then $_FILES["foo"] emits the exact notification you saw, and @$_FILES["foo"]["name"] === NULL.

I don't understand where you got the concept of a null file from, honestly.

According to the POST method uploads documentation at php.net, the name field in the entry in the $_FILES array is the original file name as reported by the browser. The file name used for the uploaded (temporary) file is in the tmp_name field.

The original file name must not be trusted. It is a very common attack vector, and very simple to do in practice, to supply a malicious file name and/or path, especially ones containing ../ or /../../../../../../../../ . Let that sink in for a moment, and look at what your code is doing. Yes, yes, we all know you'll add the security stuff later on, when you have free time; for now, you just want the code to work.

I'm just saying that that approach is doomed. You'd do better to do it right from the get go.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

I suspect that the primary problem is a disconnect between the HTML upload form and this PHP code. There may be a typo in the input field name, for example; or you might have forgotten the enctype="multipart/form-data" attribute from the form element.

To easily debug those, I personally use a simple PHP page that dumps out the contents of the various arrays. You can use something as simple as
PHP Code:

<?PHP
header
('Content-Type: text/plain; charset=UTF-8');

echo 
"GET:\n"var_dump(@$_GET);
echo 
"\nPOST:\n"var_dump(@$_POST);
echo 
"\nFILES:\n"var_dump(@$_FILES);
?>

although I personally prefer a nice nested HTML table. If you have that somewhere on your development server, you can temporarily change the action of the form element to point to that, and look at exactly what fields the browser sends. If there are any errors in the output, you need to fix the upload form.

If you use a single PHP file to both provide the upload form and to process it, you must understand that when the client browser asks for the form first, there will be no POST data, no FILES: it is a normal GET request.

When you save a file uploaded by a client, and you wish to use the original file name, you should apply some serious sanitization to the $_FILES["foo"]["name"] value before using it. The most robust approach I can think of is to first obtain a description of all uploaded files, something like
Code:

$uploads = 0;            /* Number of uploaded files */
$upload_temp = array();  /* Temporary filename */
$upload_size = array();  /* Uploaded file size in bytes */
$upload_html = array();  /* Field name in HTML code */
$upload_name = array();  /* Original filename, untrustworthy */
$upload_mime = array();  /* Upload mime type, untrustworthy */
$upload_errors = array(); /* Error codes and their counts */

foreach ($_FILES as $htmlname => $info)
    if (is_array(@$info["error"])) {
        foreach ($info["error"] as $key => $error)
            if ($error === 0) {
                $upload_temp[$uploads] = @$info["tmp_name"][$key];
                $upload_size[$uploads] = @$info["size"][$key];
                $upload_html[$uploads] = $htmlname;
                $upload_name[$uploads] = @$info["name"][$key];
                $upload_mime[$uploads] = @$info["type"][$key];
                $uploads++;
            } else
                $upload_errors[$error]++;
    } else
    if (@$info["error"] === 0) {
        $upload_temp[$uploads] = @$info["tmp_name"];
        $upload_size[$uploads] = @$info["size"];
        $upload_html[$uploads] = $htmlname;
        $upload_name[$uploads] = @$info["name"];
        $upload_mime[$uploads] = @$info["type"];
        $uploads++;
    } else
        $upload_errors[@$info["error"]]++;

which works even when multiple files are selected, and completely ignores the HTML names given to the file input entries. If you use Javascript or similar to use multiple copies of the same file input element in the HTML, remember to specify the name as an array, ie. in HTML, <input type="file" name="foo[]" ... .

If there are errors, it usually means the entire upload is shot. I for one would not trust any part of a failed upload.

Next, I'd clean up the $upload_name array. My preferred tool for that is preg_replace(), something like the following:
Code:

for ($u = 0; $u < $uploads; $u++) {
    $name = $upload_name[$u];

    /* Remove any leading directory components. */
    $name = preg_replace('/^.*[\\:\/]+/', "", $name);

    /* Keep only alphanumerics, dashes, underscores, full stops. */
    $name = preg_replace('/[^-.0-9A-Z_a-z]+/', "", $name);

    /* A full stop must be preceded and followed by a number or letter. */
    $name = preg_replace('/[^0-9A-Za-z]*\.[^0-9A-Za-z]*/', "", $name);

    /* Make sure the name starts and stops with a number or letter. */
    $name = preg_replace('/^[^0-9A-Za-z]+/', "", $name);
    $name = preg_replace('/[0-9A-Za-z]+$/', "", $name);

    /* Note: $name may be empty, if it was bad enough. */

    $upload_name[$u] = $name;
}

I've never used the $upload_mime array, as the contents are usually completely bogus. For example, people using Windows, have a lot of JPEG files named with a .gif suffix, and therefore boldly claimed to be image/gif by the browser. Incorrectly.

In fact, I only use the tmp_name, size, and after heavy filtering as above, name.

I assure you, this all works if you have your Apache correctly configured, proper PHP settings allowing file uploads, and a working PHP script. If you cannot get yours to work, one of those is incorrect.

errigour 06-26-2012 01:20 PM

Yea It works fine without the two lines I posted. Maybe you could help me, I want to check to make sure the file name is an image file otherwise people will wonder why they could post strange files and see nothing but a missing image box on the page.

Here's the form in action
http://o0oo0.net16.net/Post Picture/

Try and post a file that's not an image.

Here's the html form:
Code:

<form action="Upload File.php" method="post" enctype="multipart/form-data">

        <h1>
            Post A Picture
        </h1>

        <p>
            <label>File to upload:</label>
            <input id="file" type="file" name="file">
            <input id="submit" type="submit" name="submit" value="Submit">
        </p>
</form>


Nominal Animal 06-26-2012 08:52 PM

Quote:

Originally Posted by errigour (Post 4712653)
I want to check to make sure the file name is an image file otherwise people will wonder why they could post strange files and see nothing but a missing image box on the page.

I personally do that using getimagesize(). Although it is a GD function, it does not require the GD library; meaning it should work even when GD itself is not available.

Code:

$info = @getimagesize(@$_FILES["file"]["tmp_name"]);
$name = FALSE;
$error = array();

if (is_array($info) && count($info) >= 3) {

    /* Check uploaded image type. */
    switch ($info[2]) {
    case IMAGETYPE_GIF:  $name = ".gif"; break;
    case IMAGETYPE_PNG:  $name = ".png"; break;
    case IMAGETYPE_JPEG: $name = ".jpg"; break;
    default:            $name = FALSE;
                        $error[] = "Uploaded file is not a GIF, JPEG, or PNG image.";
    }

    /* Only allow 100 .. 3200 pixels wide images. */
    if ($info[0] < 100) {
        $name = FALSE;
        $error[] = "Image is not wide enough.";
    }
    if ($info[0] > 3200) {
        $name = FALSE;
        $error[] = "Image is too wide.";
    }

    /* Only allow 100 .. 3200 pixels tall images. */
    if ($info[1] < 100) {
        $name = FALSE;
        $error[] = "Image is not tall enough.";
    }
    if ($info[1] > 3200) {
        $name = FALSE;
        $error[] = "Image is too tall.";
    }
}

/* Use the original file name, if it is an image. */
if ($name !== FALSE) {
    $temp = @$_FILES["file"]["name"];
    $temp = preg_replace('/^.*\/+/', "", $temp);
    $temp = preg_replace('/\.[^.]*$/', "", $temp);
    $temp = preg_replace('/[^-0-9A-Z_a-z]+/', "", $temp);
    $temp = preg_replace('/^[^0-9A-Za-z]+/', "", $temp);
    $temp = preg_replace('/[^0-9A-Za-z]+$/', "", $temp);
    if (strlen($name) > 0)
        $name = $temp . $name;
    else {
        $name = FALSE;
        $error[] = "Original image file name cannot be used; please rename file first.";
    }
}

/*
 * At this point:
 *    if ($name !== FALSE) {
 *        the uploaded file is an image, and $name is a suitable
 *        permanent file name for it.
 *    } else
 *    if (count($error) < 1) {
 *        there was no uploaded file.
 *    } else {
 *        the entries in the $error array tell the user why
 *        the uploaded file is unacceptable. For example:
 *        foreach ($error as $msg) echo $msg, "<br>\n";
 *    }
*/


errigour 06-27-2012 05:57 AM

For some reason it doesn't seem to work for me.

---------- Post added 06-27-12 at 06:58 AM ----------

Code:

    $info = getimagesize(@$_FILES["file"]["tmp_name"]);
    $name = FALSE;
    $error = array();

    if (is_array($info) && count($info) >= 3)
    {

        /* Check uploaded image type. */
        switch ($info[2])
        {
            case IMAGETYPE_GIF:  $name = ".gif"; break;
            case IMAGETYPE_PNG:  $name = ".png"; break;
            case IMAGETYPE_JPEG: $name = ".jpg"; break;
            case IMAGETYPE_JPEG: $name = ".jpeg"; break;
            default:            $name = FALSE;
        }
    }

    if( $name = FALSE )
    {
        echo "Uploaded file is not a GIF, JPEG, or PNG image.<BR>\n";
        include('index.html');
        exit;
    }


Nominal Animal 06-27-2012 07:18 AM

Quote:

Originally Posted by errigour (Post 4713202)
For some reason it doesn't seem to work for me.

That's weird. 000webhost.com does have GD installed for PHP. What happens, exactly?

To debug partial failures (like POST data being intact but uploaded file missing), add
Code:

echo "<!-- Files:\n";
var_dump(@$_FILES);
echo "\n-->";

in your PHP page somewhere, so you can see the exact contents of the $_FILES array by looking at the page source.

errigour 06-27-2012 08:49 AM

I'm testing it on my home page I didn't try with web host, also why do you add the two echo lines to that code?

Nominal Animal 06-27-2012 10:12 AM

Quote:

Originally Posted by errigour (Post 4713321)
why do you add the two echo lines to that code?

So that the dump is in a HTML comment.

Here is a tested, working, but very bare-bones upload script:
Code:

<?PHP

    header('Content-Type: text/html; charset=utf-8');

    define('UPLOADS_DIR', 'path-to-upload-directory');
    define('UPLOADS_URL', 'url-to-upload-directory');

?><html>
 <head>
  <title> Upload test </title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 </head>
 <body>

<?PHP

    $uploads = 0;
    $upload_name = array(); /* Original names */
    $upload_temp = array(); /* Temporary names */
    $upload_size = array(); /* Size in bytes */
    $upload_info = array(); /* Information */

    foreach (@$_FILES as $set)
        if (is_array($set["error"])) {
            foreach ($set["error"] as $key => $error)
                if ($error === 0) {
                    $uploads++;
                    $upload_name[$uploads] = $set["name"];
                    $upload_temp[$uploads] = $set["tmp_name"];
                    $upload_size[$uploads] = $set["size"];
                    $upload_info[$uploads] = array();
                }
        } else
        if ($set["error"] === 0) {
            $uploads++;
            $upload_name[$uploads] = $set["name"];
            $upload_temp[$uploads] = $set["tmp_name"];
            $upload_size[$uploads] = $set["size"];
            $upload_info[$uploads] = array();
        }

    for ($u = 1; $u <= $uploads; $u++) {
        $name = $upload_name[$u];
        $upload_name[$u] = FALSE;

        if (($info = @getimagesize($upload_temp[$u])) !== FALSE) {
            switch ($info[2]) {
            case IMAGETYPE_GIF:  $ext = ".gif"; $desc = "GIF image"; break;
            case IMAGETYPE_PNG:  $ext = ".png"; $desc = "PNG image"; break;
            case IMAGETYPE_JPEG: $ext = ".jpg"; $desc = "JPEG image";break;
            default:            $ext = FALSE;
            }
            if ($ext === FALSE)
                continue;

            if ($info[0] < 16 || $info[0] > 4096 ||
                $info[1] < 16 || $info[1] > 4096)
                continue;

            $temp = $name;

            $temp = preg_replace('/^.*\/+/', "", $temp);
            $temp = preg_replace('/\.[^\.]*$/', "", $temp);
            $temp = preg_replace('/[^-0-9A-Z_a-z]+/', "", $temp);
            $temp = preg_replace('/^[^0-9A-Za-z]+/', "", $temp);
            $temp = preg_replace('/[^0-9A-Za-z]+$/', "", $temp);
            if (strlen($temp) < 1)
                continue;

            $upload_info[$u]["original"] = $name;
            $upload_info[$u]["filesize"] = $upload_size[$u];
            $upload_info[$u]["width"] = $info[0];
            $upload_info[$u]["height"] = $info[1];
            $upload_info[$u]["type"] = $info[2];
            $upload_info[$u]["desc"] = $desc;

            /* Note: should check against overwriting existing files here!
            */

            if (@move_uploaded_file($upload_temp[$u], UPLOADS_DIR . "/" . $temp . $ext) !== FALSE)
                $upload_name[$u] = $temp . $ext;
        }
    }

    for ($u = 1; $u <= $uploads; $u++)
        if ($upload_name[$u] !== FALSE) {
            $url = UPLOADS_URL . "/" . htmlentities($upload_name[$u], ENT_QUOTES, "utf-8");
            echo '<p><a href="', $url, '"><img src="', $url,
                '" width="', $upload_info[$u]["width"],
                '" height="', $upload_info[$u]["height"],
                '" alt="',
                '" title="', htmlentities($upload_info[$u]["original"], ENT_QUOTES, "utf-8"),
                ' - ', $upload_info[$u]["width"], "x", $upload_info[$u]["height"],
                ' ', $upload_info[$u]["desc"], '" border="0">',
                "</a></p>\n";
        }

?>

  <form action="upload.php" method="post" enctype="multipart/form-data" accept-charset="utf-8">
  <fieldset>
    <legend> Image Upload </legend>
    <input type="file" name="image">
    <input type="submit" value="Upload">
  </fieldset>
  </form>

 </body>
</html>

This script both provides the upload form, and handles the upload itself, when saved as upload.php. For brevity, I dropped the error messages; it does check everything except it blithely overwrites already existing files in the upload directory.

It only accepts GIF, PNG, and JPEG images between 16x16 and 4096x4096 pixels; all other uploaded files are discarded. The original name, image type, and dimensions are shown in the image tooltip.


All times are GMT -5. The time now is 09:51 AM.