Problem with writing to a file

Hi,

So I have a problem with the code. It should write to the data.csv file, but it does not create it nor write to it if I create it manually. Would be happy if someone could help me ASAP as I need to defend this lab in a few hours :grin:

TL;DR rights for the file are 0655

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="author" content="Nikita">
	<title>LAB 5 - PHP Form</title>
</head>
<body>
	<nav>
  		<ul>
    		<li><a href="index.php">Home</a></li>
    		<li><a href="download.php">Download Data</a></li>
  		</ul>
	</nav>
	<h1>Registration Form</h1>
	<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
	<label for="nameFirst">First Name:</label>
	<input type="text" id="nameFirst" name="nameFirst" required><br><br>
	<label for="nameMiddle">Middle Name:</label>
	<input type="text" id="nameMiddle" name="nameMiddle"><br><br>
	<label for="nameLast">Last Name:</label>
	<input type="text" id="nameLast" name="nameLast" required><br><br>
	<label for="salutation">Salutation:</label>
	<select id="salutation" name="salutation" required>
		<option value="Mr.">Mr.</option>
		<option value="Ms.">Ms.</option>
		<option value="Mrs.">Mrs.</option>
		<option value="Sir">Sir</option>
		<option value="Prof.">Prof.</option>
		<option value="Dr.">Dr.</option>
	</select><br><br>
	<label for="age">Age:</label>
	<input type="number" id="age" name="age" required min="18" max="98"><br><br>
	<label for="email">Email:</label>
	<input type="email" id="email" name="email" required><br><br>
	<label for="phone">Phone(Including country code):</label>
	<input type="tel" id="phone" name="phone" required><br><br>
	<label for="dateArrive">Date of Arrival:</label>
	<input type="date" id="dateArrive" name="dateArrive" required><br><br>
	<input type="submit" name="submit" value="Submit">
</form>
<?php
// Define an array to store validation errors
    $errors = array();

// Check if the form has been submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST') {

     // Validate first name
        if (isset($_POST['nameFirst']) && !preg_match('/^[a-zA-Z]+$/i', $_POST['nameFirst'])) {
            $errors[] = 'First name must not contain digits or special characters';
        }

        // Validate middle name
        if (isset($_POST['nameMiddle']) && !preg_match('/^[a-zA-Z]+$/i', $_POST['nameMiddle'])) {
            $errors[] = 'Middle name must not contain digits or special characters';
        }

        // Validate last name
        if (isset($_POST['nameLast']) && !preg_match('/^[a-zA-Z]+$/i', $_POST['nameLast'])) {
            $errors[] = 'Last name must not contain digits or special characters';
        }

    // Validate salutation
$allowedSalutations = array('Mr.', 'Ms.', 'Mrs.', 'Sir', 'Prof.', 'Dr.');
if (isset($_POST['salutation']) && !in_array($_POST['salutation'], $allowedSalutations)) {
    $errors[] = 'Invalid salutation';
}

    // Validate age
if (isset($_POST['age']) && ($_POST['age'] < 18 || $_POST['age'] > 98)) {
    $errors[] = 'Age must be between 18 and 98';
}

// Validate email
if (isset($_POST['email']) && !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
    $errors[] = 'Invalid email address';
}

// Validate phone number
if (isset($_POST['phone']) && !preg_match('/^(\+?\d{1,3}[\s-]?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/', $_POST['phone'])) {
    $errors[] = 'Invalid phone number';
}

// Validate arrival date
if (isset($_POST['dateArrive'])) {
    $minDate = new DateTime('2023-01-01');
    $maxDate = new DateTime('2033-01-01');
    $arrivalDate = DateTime::createFromFormat('Y-m-d', $_POST['dateArrive']);
    if (!$arrivalDate || $arrivalDate < $minDate || $arrivalDate > $maxDate) {
        $errors[] = 'Invalid arrival date';
    }
}

// If there are no validation errors, store the form data
if (empty($errors)) {
// Define the name of the CSV file
$filename = 'data.csv';

// Define the data to be written to the CSV file
$data = array(
    $_POST['nameFirst'],
    $_POST['nameMiddle'],
    $_POST['nameLast'],
    $_POST['salutation'],
    $_POST['age'],
    $_POST['email'],
    $_POST['phone'],
    $_POST['dateArrive'],
);

// If the file exists, add the data to it or if no file, create it
if (file_exists($filename)) {
    $file = fopen($filename, 'a');
} else {
    $file = fopen($filename, 'w');
    // Write header row
    fwrite($file, array('First Name', 'Middle Name', 'Last Name', 'Salutation', 'Age', 'Email', 'Phone', 'Date of Arrival'));
}

// Write the data to the CSV file
fwrite($file, $data);

// Close the file handle
fclose($file);

// Display a success message
echo '<p><div id="confirmedText">Thank you for registering!</p>';
echo '<p>Registration details:</p>';
echo '<ul>';
echo '<li>Name: '.$_POST['salutation'].' '.$_POST['nameFirst'].' '.$_POST['nameMiddle'].' '.$_POST['nameLast'].'</li>';
echo '<li>Age: '.$_POST['age'].'</li>';
echo '<li>Email: '.$_POST['email'].'</li>';
echo '<li>Phone: '.$_POST['phone'].'</li>';
echo '<li>Date of Arrival: '.$_POST['dateArrive'].'</li>';
echo '</ul>';
} else {
// If there are validation errors, display them
echo '<ul>';
foreach ($errors as $error) {
echo '<div id="confirmedError">' . implode('<br>', $errors) . '</div>';;
}
echo '</ul>';
} }
?>

</body>
</html>

Well, you create an array of data named $data. But, you attempt to write the array, not the data inside it.
To write data from an array, you would need to do it this way:

fwrite($file, print_r($data, TRUE));

Or, you could use a FOREACH() function to parse thru the array…

It still doesn’t write anything to a file :frowning:

What output/result do you get from your code when you submit the form?

In the latest php8 version, the incorrect use of an array as the fwrite() 2nd parameter results in a fatal runtime error. Do you have php’s error_reporting set to E_ALL and display_errors set to ON, preferably in the php.ini on your system, so that php will help you by reporting and displaying all the errors it detects?

If this is part of a programming course, the course should be teaching you good programming and debugging practices.

Here’s a laundry list of things the code should be doing, most of which will simplify the code -

  1. The code for any page should be laid out in this general order - initialization, post method form processing, get method business logic - get/produce data needed to display the page, html document.
  2. To get the form to submit to the same page it is on, leave out the entire action attribute.
  3. If you put the closing </label> after the form field, you can leave out the for and corresponding id attributes.
  4. The form should be ‘sticky’ and repopulate the field values/selected option with any existing values so that the user doesn’t need to keep reentering data over and over.
  5. Any value that you output in a html context should have htmlentities applied to it to help prevent cross site scripting.
  6. For the required attribute to work with a select/option menu, the first option must have an empty string for the value and is typically a prompt to select one of the choices.
  7. The middle name field isn’t required, but the server-side validation doesn’t allow an empty string as a value. An empty string for a value should bypass the existing server-side validation.
  8. A person’s age is not a constant value unless they are dead. You should use the date of birth, and calculate the age when needed.
  9. Fields that must have a specific format, such as the phone, should include an example of the expected format either in the label or as a placeholder.
  10. After you have detected that a post method form has been submitted, you should trim all form data. This will allow you to detect any field that was all white-space characters.
  11. You should then validate if a field is an empty string or not. You would then only apply the preg_match() logic to fields that are not an empty string.
  12. After you have detected that a post method form has been submitted, all the fields, except for uncheck checkbox/radio-buttons, will be set. There’s no good reason to test if an always set field isset(). This is just a waste of typing and actually hides mistakes.
  13. You can replace the fopen/fwrite/fclose logic with file_put_contents() statements with the FILE_APPEND flag.
  14. You must use file locking and have error handling for the file operations so that concurrent instances of your script won’t corrupt the data file (this is why using a database is the preferred method for storing data, since the database engine performs table locking for you.)
  15. After the end of the post method form processing, if there are no errors, perform a redirect to the exact same URL of the current page to cause a get request for that page.
  16. To display a one-time success message, store it in a session variable, then test, display, and clear that session variable at the appropriate location in the html document.

Hey!

Thank you a lot for all of the tips.

I got it working. The problem was with HTML’s form method. I changed

<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

to

<form method="post" action="index.php" id="formReserve">

and it made a deal.

But only on a local server. The local server is running PHP 8.2 but my uni’s server is running PHP 7.4. Can the PHP version be the problem? What should I change so it would work on PHP 7.4?

TL;DR

Here’s the updated code. It stopped showing the validation errors.

<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="author" content="Nikita Z">
    <title>LAB 5 - PHP Form</title>
</head>
<body>
    <nav>
          <ul>
            <li><a href="index.php">Home</a></li>
            <li><a href="download.php">Download Data</a></li>
          </ul>
    </nav>
    <h1>Registration Form</h1>
    <form method="post" action="index.php" id="formReserve">
    <label for="nameFirst">First Name:</label>
    <input type="text" id="nameFirst" name="nameFirst" required><br><br>
    <label for="nameMiddle">Middle Name:</label>
    <input type="text" id="nameMiddle" name="nameMiddle"><br><br>
    <label for="nameLast">Last Name:</label>
    <input type="text" id="nameLast" name="nameLast" required><br><br>
    <label for="salutation">Salutation:</label>
    <select id="salutation" name="salutation" required>
        <option value="Mr.">Mr.</option>
        <option value="Ms.">Ms.</option>
        <option value="Mrs.">Mrs.</option>
        <option value="Sir">Sir</option>
        <option value="Prof.">Prof.</option>
        <option value="Dr.">Dr.</option>
    </select><br><br>
    <label for="age">Age:</label>
    <input type="number" id="age" name="age" required min="18" max="98"><br><br>
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required><br><br>
    <label for="phone">Phone(Including country code):</label>
    <input type="tel" id="phone" name="phone" required><br><br>
    <label for="dateArrive">Date of Arrival:</label>
    <input type="date" id="dateArrive" name="dateArrive" required><br><br>
    <input type="submit" id="submitReservation" name="submit" value="Submit">
</form>
<?php

//Set error reporting to all
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// Define an array to store validation errors
    $errors = array();

// Check if the form has been submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST') {

     // Validate first name
        if (isset($_POST['nameFirst']) && !preg_match('/^[a-zA-Z]+$/i', $_POST['nameFirst'])) {
            $errors[] = 'First name must not contain digits or special characters';
        }

        // Validate middle name
        if (isset($_POST['nameMiddle'])) {
    if ($_POST['nameMiddle'] === '') {
        // Middle name is empty
    } else if (!preg_match('/^[a-zA-Z]+$/i', $_POST['nameMiddle'])) {
        $errors[] = 'Middle name must not contain digits or special characters';
    }
}

        // Validate last name
        if (isset($_POST['nameLast']) && !preg_match('/^[a-zA-Z]+$/i', $_POST['nameLast'])) {
            $errors[] = 'Last name must not contain digits or special characters';
        }

    // Validate salutation
$allowedSalutations = array('Mr.', 'Ms.', 'Mrs.', 'Sir', 'Prof.', 'Dr.');
if (isset($_POST['salutation']) && !in_array($_POST['salutation'], $allowedSalutations)) {
    $errors[] = 'Invalid salutation';
}

    // Validate age
if (isset($_POST['age']) && ($_POST['age'] < 18 || $_POST['age'] > 98)) {
    $errors[] = 'Age must be between 18 and 98';
}

// Validate email
if (isset($_POST['email']) && !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
    $errors[] = 'Invalid email address';
}

// Validate phone number
if (isset($_POST['phone']) && !preg_match('/^(\+?\d{1,3}[\s-]?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/', $_POST['phone'])) {
    $errors[] = 'Invalid phone number';
}

// Validate arrival date
if (isset($_POST['dateArrive'])) {
    $minDate = new DateTime('2023-01-01');
    $maxDate = new DateTime('2033-01-01');
    $arrivalDate = DateTime::createFromFormat('Y-m-d', $_POST['dateArrive']);
    if (!$arrivalDate || $arrivalDate < $minDate || $arrivalDate > $maxDate) {
        $errors[] = 'Invalid arrival date';
    }
}

// If there are no validation errors, store the form data
if (empty($errors)) {
// Define the name of the CSV file
$filename = 'data.csv';

// Define the data to be written to the CSV file
$data = array(
    $_POST['nameFirst'],
    $_POST['nameMiddle'],
    $_POST['nameLast'],
    $_POST['salutation'],
    $_POST['age'],
    $_POST['email'],
    $_POST['phone'],
    $_POST['dateArrive'],
);

// Convert the data array to a string
$data_string = implode(";", $data) . "\n";

// If the file exists, add the data to it or if no file, create it
if (file_exists($filename)) {
    $file = fopen($filename, 'a');
} else {
    $file = fopen($filename, 'w');
    // Write header row
    fwrite($file, "First Name;Middle Name;Last Name;Salutation;Age;Email;Phone;Date of Arrival\n");
}

// Write the data to the CSV file
fwrite($file, $data_string);

// Close the file handle
fclose($file);

// Display a success message
echo '<p><div id="confirmedText">Thank you for registering!</p>';
echo '<p>Registration details:</p>';
echo '<ul>';
echo '<li>Name: '.$_POST['salutation'].' '.$_POST['nameFirst'].' '.$_POST['nameMiddle'].' '.$_POST['nameLast'].'</li>';
echo '<li>Age: '.$_POST['age'].'</li>';
echo '<li>Email: '.$_POST['email'].'</li>';
echo '<li>Phone: '.$_POST['phone'].'</li>';
echo '<li>Date of Arrival: '.$_POST['dateArrive'].'</li>';
echo '</ul>';
 

// Add a "Download Registration Details" button
 
    echo '<form method="post" action="download.php">';
    echo '<input type="hidden" name="salutation" value="'.$_POST['salutation'].'">';
    echo '<input type="hidden" name="nameFirst" value="'.$_POST['nameFirst'].'">';
    echo '<input type="hidden" name="nameMiddle" value="'.$_POST['nameMiddle'].'">';
    echo '<input type="hidden" name="nameLast" value="'.$_POST['nameLast'].'">';
    echo '<input type="hidden" name="age" value="'.$_POST['age'].'">';
    echo '<input type="hidden" name="email" value="'.$_POST['email'].'">';
    echo '<input type="hidden" name="phone" value="'.$_POST['phone'].'">';
    echo '<input type="hidden" name="dateArrive" value="'.$_POST['dateArrive'].'">';
    echo '<button type="submit" name="submit">Download Registration Details</button>';
    echo '</form>';
}
}


else {
// If there are validation errors, display them to the user
echo '<div id="confirmedError">';
echo '<p>Please fix the following errors:</p>';
echo '<ul>';
foreach ($errors as $error) {
echo '<li>' . $error . '</li>';
}
echo '</ul>';
}



?>

</body>
</html>

If you do item #1 on the list of organizing the code on the page, and also consistently indent it, you can probably see why the errors are not being displayed.

Sponsor our Newsletter | Privacy Policy | Terms of Service