As you've spend the whole day on this, let me give you a bunch of pointers. I hope you can learn something from it and understand why those "Undefined" and "Notices" are there. I've not tested the code, but if you go thru all the comments I hope you'll understand and will be able to make it getting to work.
<?php
// Always start sessions first:
// if your db.php throws an error, the session can't start anymore
// and throws a warning
session_start();
require('db.php');
// Do check if a variable exists. PHP should throw you a warning otherwise.
if(empty($_SESSION['logged_in']) || $_SESSION['logged_in'] != 1) {
$_SESSION['message'] = "You must log in before viewing your profile page!";
header("Location: error.php");
// Stop running the script after a redirect!
// A header is an instruction, a client
// might simple ignore it and show the page content anyway
exit();
}
// Check if the variable exists!
// Long way:
// if(isset($_POST['stid'])) { $postedId = $_POST['stid'] } else { $postedId = false; }
// Medium way:
// $postedId = (isset($_POST['stid']) ? $_POST['stid'] : false;
// Short way:
$postedId = $_POST['stid']?:false;
// Make your query look nice, makes your life easy and debugging too
// Query questions:
// 1. What if $_SESSION['tcid'] doesn't exist?
// 2. What if $postedId doesn't exist?
// 3. What if $postedId is 0; DROP TABLE students; ?
// Remember, a client can send anything via $_POST['stid']
//
//$qry = "SELECT stcontents.id, `st_id`, `name`
// FROM `students`, `stcontents`
// WHERE stcontents.tc_id = " . $_SESSION['tcid'] . "
// AND students.id = st_id
// AND st_id = " . $postedId . " GROUP BY st_id";
//
// Read about mysqli_real_escape_string
// https://www.php.net/manual/en/mysqli.real-escape-string.php
// Want to do it really right? Use prepared statements
// https://www.php.net/manual/en/mysqli.prepare.php
$qry = "SELECT stcontents.id, `st_id`, `name`
FROM `students`, `stcontents`
WHERE stcontents.tc_id = " . mysqli_real_escape_string($mysqli, $_SESSION['tcid']) . "
AND students.id = st_id
AND st_id = " . mysqli_real_escape_string($mysqli, $postedId) . " GROUP BY st_id";
$result = mysqli_query($mysqli, $qry);
$row = mysqli_fetch_array($result);
// But what if no result was found?
if(empty($postedId) || empty($row)) {
exit('Something above went wrong!');
}
?>
<!doctype html>
<html lang="en">
<body>
<div class="container" id="turma-container">
<!--
// Leave out the action if it's empty anyway
// https://stackoverflow.com/questions/1131781/is-it-a-good-practice-to-use-an-empty-url-for-a-html-forms-action-attribute-a
-->
<form method="post" enctype="multipart/form-data">
<p>Image:</p>
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload Image" name="submit">
</form>
<?php
$target_dir = "resources/images/"; // Better use the full path
// $target_file = $target_dir."img".$postedId.".jpg";
// What if $postedId is /../../logo ?
// Is resources/images/img/../../logo.jpg a valid path?
//
// I'll assume $postedId will be an integer (number)
// using https://www.php.net/manual/en/function.settype.php
settype($postedId, 'int');
// Another approach: basename()
// https://www.php.net/manual/en/function.basename.php
// https://www.php.net/manual/en/features.file-upload.post-method.php
$target_file = $target_dir . basename("img" . $postedId . ".jpg");
$uploadOk = 1;
// $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
// You have just made a string $target_file.. so
// nothing is there, or it would be jpg anyway, since you've said ".jpg"
if(isset($_POST["submit"])) {
// So $_POST['submit'] might be there, but was the fileToUpload too?
if(empty($_FILES["fileToUpload"])) {
exit('no file!');
}
// $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
//
// Well although getimagesize indeed does return false on failure,
// read the caution "Do not use to check that a given file is a valid image."
// here https://www.php.net/manual/en/function.getimagesize.php
// the path it also incomplete ($target_dir is missing)
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if($mime = finfo_file($finfo, $_FILES["fileToUpload"]["tmp_name"])) {
if($mime == 'image/jpg' || $mime == 'image/jpeg') {
// Now you could use getimagesize as extra check
// But there might be better alternatives
if(getimagesize($_FILES["fileToUpload"]["tmp_name"]) === false) {
echo "File is corrupt";
$uploadOk = 0;
} else {
echo "File is an image - " . $mime . ".";
$uploadOk = 1;
}
} else {
echo $mime . " is not supported.";
$uploadOk = 0;
}
} else {
echo "Invalid file";
$uploadOk = 0;
}
if($_FILES["fileToUpload"]["size"] > 500000) {
echo "Sorry, your file is too large.";
$uploadOk = 0;
}
// if($imageFileType != "jpg") {
// echo "Sorry, only JPG files are allowed.";
// $uploadOk = 0;
// }
//
// Done this above.
// If the idea is some pre-flight check, consider $_FILES['fileToUpload']['type']
if($uploadOk == 0) {
echo "Sorry, your file was not uploaded.";
} else {
if(move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file ". basename($_FILES["fileToUpload"]["name"]). " has been uploaded.";
} else {
echo "Sorry, there was an error uploading your file.";
}
}
}
?>
</div>
</body>
</html>
There can still be a lot of optimization, but this should get you going. Best of luck with it! If you have some questions, feel free to comment.
After your comments, let's do a new round!
Here is the code again:
<?php
session_start();
require 'db.php';
// So empty($var) returns true/false based on if a variable exists (isset()) and it's value
// Read: https://www.php.net/empty what is considered FALSE is it exists
// I'm guessing this will do:
if (empty($_SESSION['logged_in'])) {
$_SESSION['message'] = "You must log in before viewing your profile page!";
header("location: error.php");
exit();
} else {
// If you are sure $_SESSION['name'] exists if a user is logged in, this is fine.
// Otherwise consider $name = $_SESSION['name']?:'unknown';
$name = $_SESSION['name'];
}
if (isset($_POST['stid'])) {
// So you still allow a raw POST variable in your database query..
// Don't do that or you might find someone messed around with your database.
// https://www.w3schools.com/sql/sql_injection.asp
// $pstid = $_POST['stid'];
$pstid = mysqli_real_escape_string($link, $_POST['stid']);
$tcid = mysqli_real_escape_string($link, $tcid); // Where does $tcid come from? Does it exist?
// Check if the query is succesful and if there are results..
// In the function documentation always peek at the Parameters and Return Values
// https://php.net/manual/en/mysqli.query.php : Returns FALSE on failure.
// https://www.php.net/manual/en/mysqli-result.fetch-array.php : Returns NULL if there are no more rows
if($result = mysqli_query($link, "SELECT `id`, `tc_id`, `name`, `essay`, `image` FROM `students` WHERE tc_id = ".$tcid." AND id = ".$pstid.";")) {
if($row = mysqli_fetch_array($result)) {
$stname = $row['name'];
$cessay = $row['essay'];
$cimage = $row['image'];
} else {
$_SESSION['message'] = "No essay was found, please create one first.";
header("location: error.php");
exit();
}
} else {
$_SESSION['message'] = "Something went wrong..";
header("location: error.php");
exit();
}
// What if $_POST['stid'] does not exist though?
// You use it as hidden input for your form, so let's throw an error.
} else {
$_SESSION['message'] = "Student id not found.";
header("location: error.php");
exit();
}
?>
<form method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="TextToUpload">Text:</label>
<!--
So, $cessay comes from your database; but how does it get entered? By students?
Imagine a students enters "</textarea><img src="https://i.imgur.com/BBcy6Wc.jpg">"
Right.. a cat picture will be shown.. Solution: Escape it.
https://www.w3schools.com/php/func_string_htmlspecialchars.asp
So:
-->
<textarea type="text" class="form-control" id="TextToUpload" rows="5" name="stessay"><?php echo $cessay; ?></textarea>
</div>
<p>Imagem do(a) aluno(a):</p>
<?php
if (isset($row['image'])) {
// Same applies here, although cimage might be under your control, so less critical
// Just make it a habbit to escape and you'll never have trouble :)
$cimage = htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
echo "<img src=\"resources/images/studentsImages/".$cimage."\">";
}
// So I've used it before in mysqli_real_escape_string, so it now could be something like '123' instead of 123
// Since we now need to escape it not for SQL but HTML, just use the original value again:
echo "<input type=\"hidden\" name=\"stid\" value=".htmlspecialchars($_POST['stid'], ENT_QUOTES, 'UTF-8').">";
?>
<input type="file" name="fileToUpload" id="fileToUpload">
<input formmethod="post" type="submit" value="savechanges" name="submit">
</form>
<?php
if(isset($_POST["submit"])) {
$essayOk = 0;
$imageOk = 0;
if(isset($_POST['stessay'])) {
$essayOk = 1;
$pessayc = mysqli_real_escape_string($link, $_POST['stessay']);
// Very good! :)
}
// Uploaded files should be in the $_FILES array! So don't use $_POST
if (isset($_FILES['fileToUpload'])) {
$target_dir = "resources/images/";
$target_file = $target_dir."img".$pstid.".jpg";
// $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); // Not needed, fails anyway
// But where is $finfo ? The code below will always fail without it..
// Adding it back:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if($mime = finfo_file($finfo, $_FILES["fileToUpload"]["tmp_name"])) {
if($mime == 'image/jpg' || $mime == 'image/jpeg') {
if(getimagesize($_FILES["fileToUpload"]["tmp_name"]) === false) {
echo "File is corrupt";
$uploadOk = 0;
} else {
echo "File is an image - " . $mime . ".";
$uploadOk = 1;
}
} else {
echo $mime . " is not supported.";
$uploadOk = 0;
}
} else {
echo "Invalid file";
$uploadOk = 0;
}
if ($_FILES["fileToUpload"]["size"] > 500000) {
echo "The file is too big.";
$imageOk = 0;
}
if ($imageOk == 0) {
echo "Erros sending image, try again later.";
}
}
if ($essayOk == 1) {
$query = "UPDATE students SET essay = '".$pessayc."' WHERE id = '".$pstid."';";
if (mysqli_query($link, $query)) {
echo "<p>Essay updated!</p>";
} else {
printf("Errormessage: %s\n", mysqli_error($link));
echo "<p>There was an error updating the ssay, try again later.</p>";
}
}
if ($imageOk == 1) {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file ".basename($_FILES["fileToUpload"]["name"])." was updated.";
} else {
echo "Your image was not updated, try again later.";
}
}
}
?>
As for your final question, check if it exists in the $_FILES
array, but also I believe the filename should still be in the $_POST
array. Not sure though. Add this on top of your code to see what variables are found:
print_r($_POST);
print_r($_FILES);
It will give you a nice list of POST fields and uploaded files.