1

I am attempting to create my reservation site for my class project and have been completely out of my league in regards to it. My current issue deals with the fact that for some reason, my code is throwing to my built-in error handler which verifies that variables were entered.

My goal here is to create a page which queries my database and returns which sites meet the requirements listed (dates/amenities) and are then echoed out on another page (which I am also working on).

I realize that my code is awful. To be fair, I'm pretty awful at this. As I stated in a previous post, my professor pushed me into a massive project that I had no background in and was not prepared for. I appreciate any time and help that anybody can offer.

Random thought - I think part of the problem might be that phpmyadmin uses a pretty awful format for dates (I think it's year/month/day) and that's what's throwing the error. When I tried googling the answer for that, it wanted me to transform the data through the database structure, but that option is not given through 000webhost.com (it is on my localhost).

Happy New Year!

the website: https://campease.000webhostapp.com/index.php - click campsites The header code:

<?php
 @session_start();
 require_once("includes/dbh.inc.php");
?>

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
  $('#login-trigger').click(function(){
    $(this).next('#login-content').slideToggle();
    $(this).toggleClass('active');

    if ($(this).hasClass('active')) $(this).find('span').html('&#x25B2;')
      else $(this).find('span').html('&#x25BC;')
    })
});
$(document).ready(function(){
  $('#reserve-trigger').click(function(){
    $(this).next('#reserve-content').slideToggle();
    $(this).toggleClass('active');
    })
});
$('#reserve-trigger').on('focusout', function () {
  $(this).toggleClass('active');
});
$('#login-trigger').on('focusout', function () {
  $(this).toggleClass('active');
});
</script>
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js">
<SCRIPT TYPE="text/javascript">
</script>

  <script>
  $(document).ready(function() {  $("#startdate").datepicker();  });
  $(document).ready(function() {  $("#enddate").datepicker();  });
  </script>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<header>
  <div class="container">
      <div id="branding">
        <h1><span class="highlight">Whispering</span> Winds Park</h1>
      </div>
      <nav>
          <ul>
            <li class="current"><a href="index.php">Home</a></li>
            <li><a href="mission.php">Our Mission</a></li>
            <li><a href="donate.php">Donate</a></li>
            <li><a id="reserve-trigger" href="#">Camping</a>
                <div id="reserve-content" tabindex="-1">
                <form action="includes/reserve.inc.php" method="POST">
                  <fieldset id="inputs2">
                    <ul>
                    <input id="startdate" placeholder="Start Date" />
                    <input id="enddate" placeholder="End Date"/>
                    <li id="chk"><label for="fire">Fire Pit: </label><input type="checkbox" value="Fire"></li>
                    <li id="chk"><label for="electric">Electricity: </label><input type="checkbox" value="Electric"></li>
                    <li id="chk"><label for="sewer">Sewage: </label><input type="checkbox" value="Sewer"></li>
                    <button type="submit" class="button3" name="submit1">Find a Reservation</button>
                  </ul>
                  </fieldset>
                </form>
              </div>
            </li>

<!-- /*login button*/ -->
<?php
  if (isset($_SESSION["u_uid"])) {
    echo '
    <li><form action="includes/logout.inc.php" method="POST">
    <button type="submit" class="button_1" name="Submit">Logout</button>
    </form></button></li>';
  } else {
    echo
    ' <li id="login">
      <a id="login-trigger" href="#">
        <button class="button_1">Log in <span>▼</span></button>
      </a>
      <div id="login-content" tabindex="-1">
      <form action="includes/login.inc.php" method="POST">
          <fieldset id="inputs">
            <input type="text" name="uid" placeholder="Username" required>
            <input type="password" name="pwd" placeholder="Password" required>
            <button type="submit" class="button3" name="Submit">Log In</button>
          </fieldset>
        </form>
      </div>
    </li>
    <li id="signup">
      <a href="signup.php"><button class="button_1">Sign up</button></a>
    </li>';
  }
?>
<?php
    if(isset($_SESSION["u_admin"]))
    {
echo '
<li id="signup">
  <a href="admin.php"><button class="button_1">Admin</button></a>
</li>';
}
?>

          </ul>
      </nav>
    </div>
</header>
  </body>

The retrieval code:

<?php
@session_start();
if (isset($_POST['submit1'])) {

  require_once("dbh.inc.php");

  $fire = 0;
  $electric = 0;
  $sewer = 0;

  if(isset($_POST['startdate']))
      $_SESSION['startdate'] = $_POST['startdate'];
  if(isset($_POST['enddate']))
      $_SESSION['enddate'] = $_POST['enddate'];

  if(!empty($_POST['fire'])) {
    $fire     = mysqli_real_escape_string($conn, $_POST['fire']);
  }

  if(!empty($_POST['electric'])) {
    $electric     = mysqli_real_escape_string($conn, $_POST['electric']);
  }

  if(!empty($_POST['sewer'])) {
    $sewer     = mysqli_real_escape_string($conn, $_POST['sewer']);
  }
}

if (empty($startdate) || empty($enddate)) {
  header("Location: ../index.php?index=empty_dates");
  exit();
}


$sql = "SELECT * FROM campsite WHERE water='$sewer' OR fire='$fire' OR electric = '$electric'
        AND site_id NOT IN (SELECT site_id FROM reservation
                                    where startdate = '$startdate' and '$startdate' <= '$enddate')";

$result = mysqli_query($conn, $sql);

$resultCheck = mysqli_num_rows($result);

if ($resultCheck < 1) {
header("Location: ../index.php?index=no_available_camps");
exit();
} else {

    while ($row = mysqli_fetch_assoc($result)) {

if($row = mysqli_fetch_assoc($result)) {


$siteID = mysqli_real_escape_string($conn, $_POST['site_id']);
$uid = mysqli_real_escape_string($conn, $_POST['uid']);
$start = mysqli_real_escape_string($conn, $_POST['startdate']);
$end = mysqli_real_escape_string($conn, $_POST['enddate']);
$price = mysqli_real_escape_string($conn, $_POST['s_price']);
}
// Error Handlers
// check for empty fields

if (empty($start) || empty($end)) {
 header("Locaction: ../reserve.php?=error");
 exit();
} else {
 // determine if dates are available
$sql="SELECT * from campsites where startdate<='$start' AND where startdate>'$end'";
$result = mysqli_query($conn, $sql);
$resultcheck = mysqli_num_rows($result);

if ($resultcheck > 0) {
 header("Location: ../reserve.php?=error2");
 } else {
   $sql = "INSERT INTO campsite (site_id, uid, startdate, enddate)
   VALUES ('$siteID', '$uid', '$start', '$end');";
   header("Location:./campground.php");
   exit();
  }
}
}
}
?>
tlhopbow
  • 33
  • 3
  • The format `yyyy/mm/dd` is the default format. The sql statement is potentially vulnerable to sql injection. – Professor Abronsius Jan 01 '18 at 23:35
  • `where startdate<='$start' AND where startdate>'$end'";`. The second where is invalid SQL. And you never execute the last insert query. But I'm not sure if those are the only issues. – jh1711 Jan 01 '18 at 23:36
  • Dates in `YYYY-MM-DD` are the best because they are universally recognised without any chance of being misunderstood. For example, 10/12/2017 is 12th of Oct in America and 10th of Dec for everyone else. Transforming a date from `YYYY-MM-DD` to any other format is trivial. Using [`SELECT *`](https://stackoverflow.com/questions/3639861/why-is-select-considered-harmful) is always a bad idea. You also have a [SQL Injection](https://stackoverflow.com/questions/332365/how-does-the-sql-injection-from-the-bobby-tables-xkcd-comic-work) issue. – Tigger Jan 01 '18 at 23:36
  • Thanks for those answers, I'll look up some stuff and see what I can find – tlhopbow Jan 02 '18 at 00:54

1 Answers1

1

The HTML has a few errors and the form used to search for campsites does not actually submit any of the data, most likely due to some of the errors in the HTML. A ul element can have li elements as children only - but those li elements can have other content ( typically not the best way to do it IMO in this case ) and form input elements of whatever type should have a name attribute and generally a value. In the case of the reservation form fire,electric and sewer should be named as such with a value of 1 ( refer to previous question ). The date pickers need to have names, so either instead of an ID or as well as, name them startdate and enddate as the php script is expecting them in the POST array.

If the form did successfully submit the data and the sql query ran OK, where would the results appear? I can see that the action of the form is includes/reserve.inc.php which is the second portion of code ( PHP ) but that doesn't output any content.

Editing the HTML in the browser to add attributes to the various form elements and changing their values before submitting the form yielded the following POST parameters on the live page...

startdate=01%2F03%2F2018&enddate=01%2F17%2F2018&fire=1&electric=1&sewer=1&submit1=

Whereas before only the submit1 was appearing. However there was still no result sent back.

As you already have jQuery on the page for various tasks perhaps the thing to do would be to use ajax to POST the data to the backend PHP script and use the callback to add the HTML content to the current page? Certainly something to think about perhaps.

<?php
    @session_start();
    require_once("includes/dbh.inc.php");
?>

<!DOCTYPE html>
<html>
    <head>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script>

            $(document).ready(function(){
              $('#login-trigger').click(function(){
                $(this).next('#login-content').slideToggle();
                $(this).toggleClass('active');

                if ($(this).hasClass('active')) $(this).find('span').html('&#x25B2;')
                  else $(this).find('span').html('&#x25BC;')
                })
            });

            $(document).ready(function(){
              $('#reserve-trigger').click(function(){
                $(this).next('#reserve-content').slideToggle();
                $(this).toggleClass('active');
                })
            });

            $('#reserve-trigger').on('focusout', function () {
              $(this).toggleClass('active');
            });

            $('#login-trigger').on('focusout', function () {
              $(this).toggleClass('active');
            });
        </script>
        <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js">
        <script>
            $(document).ready(function() {  $("#startdate").datepicker();  });
            $(document).ready(function() {  $("#enddate").datepicker();  });
        </script>
        <link rel="stylesheet" href="./css/style.css">
    </head>
    <body>
        <header>
            <div class='container'>
                <div id='branding'>
                    <h1><span class='highlight'>Whispering</span> Winds Park</h1>
                </div>
                <nav>
                    <ul>
                        <li class='current'><a href='index.php'>Home</a></li>
                        <li><a href='mission.php'>Our Mission</a></li>
                        <li><a href='donate.php'>Donate</a></li>
                        <li><a id='reserve-trigger' href='#'>Camping</a>
                            <div id='reserve-content' tabindex='-1'>

                                <form action='includes/reserve.inc.php' method='POST'>
                                    <fieldset>
                                        <!--

                                            child elements of a `ul` should be `li` only
                                            so you required a few more `<li></li>` around
                                            certain items here

                                            Form input elements require a name attribute and a type for the datepickers

                                        -->
                                        <ul>
                                            <li><input type='text' id='startdate' name='startdate' placeholder='Start Date' /></li>
                                            <li><input type='text' id='enddate' name='enddate' placeholder='End Date'/></li>
                                            <!--

                                                The checkboxes require a name attribute otherwise they will not appear
                                                in the POST array data. Set the value to `1` as it is a bit stored in 
                                                the db anyway

                                            -->
                                            <li><label for='fire'>Fire Pit: </label><input type='checkbox' name='Fire' value=1></li>
                                            <li><label for='electric'>Electricity: </label><input type='checkbox' name='Electric' value=1></li>
                                            <li><label for='sewer'>Sewage: </label><input type='checkbox' name='Sewer' value=1></li>
                                            <li><button type='submit' class='button3' name='submit1'>Find a Reservation</button></li>
                                        </ul>
                                    </fieldset>
                                </form>

                            </div>
                        </li>

                        <!-- /*login button*/ -->
                        <?php
                            if( isset( $_SESSION["u_uid"] ) ) {
                                echo '
                                <li>
                                    <form action="includes/logout.inc.php" method="POST">
                                        <button type="submit" class="button_1" name="Submit">Logout</button>
                                    </form>
                                </li>';

                            } else {

                                echo
                                '<li id="login">
                                    <a id="login-trigger" href="#">
                                        <button class="button_1">Log in <span>▼</span></button>
                                    </a>
                                    <div id="login-content" tabindex="-1">
                                        <form action="includes/login.inc.php" method="POST">
                                            <fieldset id="inputs">
                                                <input type="text" name="uid" placeholder="Username" required>
                                                <input type="password" name="pwd" placeholder="Password" required>
                                                <button type="submit" class="button3" name="Submit">Log In</button>
                                            </fieldset>
                                        </form>
                                    </div>
                                </li>
                                <li id="signup">
                                    <a href="signup.php"><button class="button_1">Sign up</button></a>
                                </li>';
                            }
                            if( isset( $_SESSION["u_admin"] ) ) {
                                echo '
                                <li id="signup">
                                  <a href="admin.php"><button class="button_1">Admin</button></a>
                                </li>';
                            }
                        ?>
                  </ul>
                </nav>
            </div>
        </header>
    </body>
</html>

Moving on to the backend script.

Do you have tables named campsite and campsites? The sql statements all have embedded variables which, despite the use of mysqli_real_escape_string, does leave your code potentially vulnerable to SQL Injection so you ought to use prepared statements whenever you are using user supplied input. It just takes one field that can be exploited to compromise the entire system! I could not quite follow some of the logic with what was going on there ( not enough caffeine probably yet ) so the following may be wide of the mark

<?php
    session_start();

    /* Prevent direct access to this script in the browser */
    if ( realpath(__FILE__) == realpath( $_SERVER['SCRIPT_FILENAME'] ) ) {

        /* could send a 403 but Not Found is probably better */
        header( 'HTTP/1.0 404 Not Found', TRUE, 404 );
        die( header( 'location: /index.php' ) );
    }

    if( $_SERVER['REQUEST_METHOD']=='POST' && isset( $_POST['submit1'], $_POST['startdate'], $_POST['enddate'], $_POST['fire'], $_POST['electric'], $_POST['sewer'] ) ) {

        if ( empty( $_POST['startdate'] ) || empty( $_POST['enddate'] ) ) {
            exit( header( 'Location: ../index.php?index=empty_dates' ) );
        }


        /* results from search query will be stored in this array for later use */
        $output=array();

        require_once('dbh.inc.php');

        /*
            Do startdate and enddate need to be session variables???
        */
        $startdate = filter_input( INPUT_POST,'startdate',FILTER_SANITIZE_SPECIAL_CHARS );
        $enddate = filter_input( INPUT_POST,'enddate',FILTER_SANITIZE_SPECIAL_CHARS );
        $fire = filter_var( filter_input( INPUT_POST,'fire', FILTER_SANITIZE_NUMBER_INT ), FILTER_VALIDATE_INT );
        $electric = filter_var( filter_input( INPUT_POST,'electric', FILTER_SANITIZE_NUMBER_INT ), FILTER_VALIDATE_INT );
        $sewer = filter_var( filter_input( INPUT_POST,'sewer', FILTER_SANITIZE_NUMBER_INT ), FILTER_VALIDATE_INT );

        /*
            Dates from the DatePicker are in mm/dd/yyyy
            but typically we would want to use yyyy/mm/dd
            in the database.
        */
        $startdate=DateTime::createFromFormat( 'm/d/Y', $startdate )->format('Y-m-d');
        $enddate=DateTime::createFromFormat( 'm/d/Y', $enddate )->format('Y-m-d');



        if( $fire > 1 or $fire < 0 or is_string( $fire ) ) $fire=0;
        if( $electric > 1 or $electric < 0 or is_string( $electric ) ) $electric=0;
        if( $sewer > 1 or $sewer < 0 or is_string( $sewer ) ) $sewer=0;


        $sql='select `site_id`,`uid`,`startdate`,`enddate`,`s_price` from `campsite` 
                where `water`=? and `fire`=? and `electric`=? and `site_id` not in ( 
                    select `site_id` 
                    from `reservation` 
                    where `startdate` >= ? and `startdate` <= ?
                )';

        $stmt=$conn->prepare( $sql );
        if( $stmt ){

            $stmt->bind_param('iiiss', $sewer, $fire, $electric, $startdate, $enddate );
            $result = $stmt->execute();
            $rows = $result->num_rows;

            if( $result && $rows > 0 ){

                $stmt->store_result();
                $stmt->bind_result( $id, $uid, $start, $end, $price );

                while( $stmt->fetch() ){
                    $output[]=array(
                        'site_id'   =>  $id,
                        'uid'       =>  $uid,
                        'startdate' =>  $start,
                        'enddate'   =>  $end,
                        's_price'   =>  $price
                    );
                }
                $stmt->free_result();
                $stmt->close();
                $conn->close();

                /* 
                    Now we should have an array with the recordset data from the search
                    Depending upon form submission method ( standard or ajax ) you need to
                    do something with that data. Typically you would let the user know the
                    results of the search ( otherwise what is the point of letting them search? )

                    So, you could format the results here as HTML or send back json etc
                */
                foreach( $output as $index => $site ){
                    echo "
                    <pre>
                        {$site['site_id']}
                        {$site['uid']}
                        {$site['startdate']}
                        {$site['enddate']}
                        {$site['s_price']}
                    </pre>";
                }

            } else {
                exit( header('Location: /index.php?error=no_available_camps') );
            }
        } else {
            echo "Failed to prepare sql query";
        }
    }
?>

There were other sql statements in there but as I said I couldn't quite follow the logic so the above is most likely incomplete/wrong but should helpe a little with prepared statements at least.

Other points

You have an unhandled error on the campground.php page which reveals

Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in /storage/ssd2/948/4122948/public_html/campground.php on line 110 YesYes

includes/reserve.php and /reserve.php both yield a 404-Not Found error

Perhaps use an .htaccess file within the images directory to prevent either hotlinking or directory browsing.

There are some stunning images in there but some are, to be honest, absolutely enormous and despite the majority of people having fast broadband downloading a 3.7Mb jpg as part of the HTML flow slows things somewhat - so perhaps some image optimisation would be a good idea too. That said - I'd love to go to this place myself!

Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46
  • the sql statemen above could likely be better done using the `between` operator rather than as it is currently – Professor Abronsius Jan 02 '18 at 11:33
  • RamRaider, you've truly been a blessing to my project. Like I mentioned, I really don't know what I'm doing at all, as (due to time constraints) I started running before crawling and didn't have near enough time to give myself the foundation that I needed to be a good coder on either end. Fortunately, I plan on focusing on process/business analysis, but that is no reason for me to neglect this aspect of my education. – tlhopbow Jan 04 '18 at 03:08
  • To answer your questions: The script is supposed to displayed on the campground.php page, I haven't tried using ajax because I don't actually know what it is. I've tried to focus my limited learning on php, html, and sql, while copy and pasting that jquery and praying it worked. There is only one campground table, that was a mistake. I realize that there are a number of security concerns, but this particular site will never leave the professor's desk, so I'm more worried about just finishing it off. I'd like to have it done within a week or so (if I can figure out wtf I'm doing lol). – tlhopbow Jan 04 '18 at 03:17
  • My thought was to make the dates/parameters a session variable because 1: I had an idea of how to echo out the selection and 2: I assumed that if new dates/parameters were entered, they would overwrite the existing session variables. You make it seem like that's a subpar solution and, honestly, I'm not sure how to use the language you've given me. If I'm reading correctly, it seems like the $site variable is almost the same as the $_SESSION variable and can be used in the same way? Also (because I don't know), what is the benefit of the array? I was going to use a table, but maybe that's bad? – tlhopbow Jan 04 '18 at 05:15
  • I was not trying to make your solution seem "subpar" - please do not think that. I was just curious as to how this was all supposed to work. The `$site` variable is an array which should contain the query results from the search - how that is used is unclear - but it is an entirely different thing to a `$_SESSION` variable ( the array is transient and only available after creation and before the next page load, whereas the session variable is permanent for the duration of the session unless it is unset ). In some ways a session would make sense for storing the data -at lease you could redirect – Professor Abronsius Jan 04 '18 at 07:40
  • ...cont'd > the user and display the results. It is tricky when you are doing so much of it in a single page with includes. One would usually use `includes` for functions, classes and other such scripts rather than as the action of the form because typically the form action will display results - or redirect after some processing. Displaying results in a table is perfectly fine - some will argue that is not so but for displaying data it is OK imo. Go through the code and the points I made - the form elements need names, some need `
  • ` around them (date pickers) – Professor Abronsius Jan 04 '18 at 07:46
  • I found today that you can format the datepicker like this `$( document ).ready(function() { $('#startdate').datepicker( { minDate: '0', dateFormat: 'yy/mm/dd' } ); })` – Professor Abronsius Jan 05 '18 at 17:18
  • Sorry about the late reply! I want you to know that your help has been amazing and pretty much the only thing keeping me on track. It's been a pretty hectic time in my life. Trying to work on this project, taking on a processes analysis position at work, and all the joys that a 20 day old baby can afford. This may be forward and could be against TOS (if so, I'm sorry), but do you have a spam email that you've be willing to give me so we could have switch this to more of a conversation? – tlhopbow Jan 10 '18 at 03:49