Jump to content

mac_gyver

Staff Alumni
  • Posts

    5,382
  • Joined

  • Days Won

    173

Posts posted by mac_gyver

  1. you should never disable any php error reporting level. you will end up missing things that legitimate visitors manage to do that you didn't take into account in your code and discover during testing and things that hackers do in an attempt (that fails or succeeds) to break in. you want to know when these things are occurring so that you can take appropriate action.

  2. no that's not the error number i wrote about (whatever you are using to translate replies into your native language is not working.) that's the raw error message that you DON'T want to output to visitors/hackers since it won't mean anything to a visitor and it is exactly what a hacker wants to see when they intentionally do things that trigger errors.

    the error number is in the caught exception property ->errorInfo[1]. the specific number for a duplicate index error is 1062. note: there is also a ->getCode() method, which is the sqlstate error number. this however encompasses a number of different related errors, so is not specific to a duplicate index error that you want to setup a message for to let the visitor know what was wrong with the data value that they submitted.

  3. the only database errors that are recoverable by the visitor on a site are when inserting/updating duplicate or out of range visitor submitted data. this is the only case where you should catch and handle a database statement exception, where you would test the error number in the catch logic, for things the visitor can correct, and setup a helpful message letting the visitor know exactly what was wrong with the data that they submitted. for all other error numbers, just rethrow the exception and let php catch and handle it. for all other cases, do not even put try/catch logic in your code.

    when you let php catch and handle the database exceptions, php uses its error related settings to control what happen with the actual error information, via an uncaught exception error (database statement errors will 'automatically' get displayed/logged the same as php errors.)

    so, by simply setting php's display_errors or log_errors settings (error_reporting should always be set to E_ALL), you can switch from displaying the raw database statement errors when learning, developing, and debugging, to logging the raw database statement errors on a live/public server.

    BTW - when you make the connection, you should also set emulated prepared queries to false, you want to run true prepared queries, and set the default fetch mode to assoc, so that you don't need to specify it in each fetch statement.

  4. those values are strings. they will be sorted according to the character order at each position in the string. a '1' at any position in the string, regardless of it being part of '1', '10', '1000000', is less then a '2' at that same position. you can get this to working by padding the values with leading zeros, so that each numerical field in the string is the same length.

  5. there's no field named submit in the form, and even if there was, it won't be included in the form data since it isn't a successful form control at the time the form was submitted, since the form is being submitted via an on change event. i recommend that you instead detect in the php code if a post method from was submitted. i also recommend that you log the $_POST and $_FILES data at the start of the php code so that you can see what is being submitted. none of this has anything to do with the linked to stack overflow thread.

    also in the php code, if the total size of the form data exceeds the post_max_size setting, both the $_POST and $_FILES arrays will be empty. after you have detected if a post method form was submitted, you must detect this condition and setup a message for the user that the form data was too large and could not be processed. if there is $_FILES data, you must then test the ['error'] element before using any of the uploaded file information. the ['error'] element will be a zero if the file successfully uploaded and can be processed.

    lastly, since you are using ajax to upload the file, nothing the upload.php file does in the way of redirecting will have any affect on the web page being displayed in the browser. you would want to output failure or success messages back to the ajax code to be displayed in the browser.

  6. sorry for how this sounds, but this code looks like a collection of pieces pasted together that have almost nothing to do with each other, there's missing and mismatched variables, and even an obsolete mysql_error() call in it. is this part of a programming class or self learning? what learning resources have you used to get to this point?

    next, the most immediate problem, with the text strings being assigned to variables, resulting in the non numerical error messages when you try to add them together, appears like it was intended to be the result of fetching data from the SELECT query. this code isn't even executing that query, nor is it fetching the data from it. do you have a fundamental understanding of the steps needed to build, execute, and fetch data from a SELECT query? without this knowledge, it will be impossible for you to complete this assignment.

    also, this SELECT query needs a WHERE clause in it to match the unit you are interested in, like the UPDATE query has. have you actually defined what your input data needs to be, what processing you are going to perform on that data, and what result you are trying to produce?

    regardless of this being a class assignment or a real project, you should NOT update the values to keep track of amounts, since this does not provide an audit trail that would let you know if a programming mistake, accidental key press, or nefarious activity altered the values. you should instead insert a new row of data for every transaction that affects the amounts, just like your bank, credit card, utility, ... does this.

    here are some suggestions that will modernize and simplify the code -

    1. use the much simpler PDO extension. someone has already posted a link to a tutorial on a different help forum where you have posted this.
    2. use exceptions for database statement errors and in most cases simply let php catch the exception. this will let you remove any existing database statement error handling logic since it will no longer get executed upon an error, simplifying the code.
    3. name the database connection variable as to the type of connection it holds, such as $mysqli or $pdo, then use this variable name throughout the code. this is the cause of the undefined $msyqli variable error. your code is putting the database connection into a variable named $link, not $mysqli. if you are not getting this fundamental requirement of using the same variable for a particular purpose through out the code, you are not going to be able to complete this assignment. 
    4. don't copy variables to other variables for nothing. just use the original variables that the data is in.

     

  7. what you are trying to do is dynamically process data using a data-driven design, rather than to write out repeated code and variables for every possible field. if you search the forum for that phrase, you will find some examples. 

    you need a data structure (array, db table) that holds a definition of all the dynamic values associated with each field in a set, such the field name, a human readable label, a type, validation rules, processing rules, multi choice/select values, ... you would then loop over the data in this defining structure and use simple, general-purpose code to operate on the actual data. i typically use the field name as the defining array's index values, since the field name/index must be unique. the label gets used when building error messages, as a label for form fields, as html table headings, e.g. what you mentioned, ... the type is used to control any different processing, via a switch/case statement. validation rules include required validation, format validation, value (range) validation, character class validation. processing rules control being used in an insert query, the set part of an update query, the where part of an update query, in the where part of a delete query, in an email body, in an email header, ...

  8. yes it is using the PDO extension. you can tell from the fetch mode being used, but this doesn't actually matter, because the database specific code is only querying for all the matching data, then indexing/pivoting it using the parent id value. that's not anything that's specific to the database extension. PDO just happens to have a fetch mode that will do this for you.

    you do realize that this processing is exactly what i just posted in your other thread, just with different names?

  9. the first section of code is just indexing/pivoting the data, using the parent id, when fetching it. there's actually a PDO fetch mode that will do this for you if you select the parent_id as the first column in the SELECT list - PDO::FETCH_GROUP

    next, you need a recursive function to loop over the data and output it the way you want. see the following example (should be close to what your db naming is) -

    <?php
    
    // create/display nested comments
    
    // init
    require 'pdo_connection.php';
    
    // fake some data
    $user_id = 1;
    $_GET['news_id'] = 1;
    
    $post = []; // array to hold a trimmed working copy of the form data
    $errors = []; // array to hold user/valdiation errors
    
    // post
    if($_SERVER['REQUEST_METHOD'] == 'POST')
    {
    	// trim all the data at once
    	$post = array_map('trim',$_POST); // if any input is an array, use a recursive trim call-back function here instead of php's trim
    	
    	// validate inputs here...
    	
    	// if no errors, use the form data
    	if(empty($errors))
    	{
    		$sql = "INSERT comment (news_id, parent_id, user_id, comment, datetime) VALUE (?,?,?,?,NOW())";
    		$stmt = $pdo->prepare($sql);
    		$stmt->execute([ $_GET['news_id'], $post['parent_id'], $user_id, $post['comment'] ]);
    	}
    	
    	// if no errors, success
    	if(empty($errors))
    	{
    		die(header("Refresh:0"));
    	}
    }
    
    // get all the rows of data for the requested news id
    $sql = "SELECT parent_id, id, news_id, user_id, comment
     FROM comment
     WhERE news_id = ?
     ORDER BY datetime";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([ $_GET['news_id'] ]);
    $comment_data = $stmt->fetchAll(PDO::FETCH_GROUP);
    
    // recursive function to output parent/child data
    function list_comments($parent_id, $data, $level=0)
    {
    	// this just supplies a visual part to the output so you can see what the code does
    	$indent = str_repeat("---- ", $level);
    	
    	// loop over data for the current parent_id
    	foreach($data[$parent_id] as $arr)
    	{
    		// output the comment and any other information
    		echo "$indent{$arr['comment']}<br>";
    		// determine and output any child count
    		$count = isset($data[$arr['id']]) ? count($data[$arr['id']]) : 0;
    		$pl = $count == 0 || $count > 1 ? 'ies' : 'y';
    		echo "$indent$count Repl$pl<br>";
    		// allow a comment for the current parent
    		// you would probably want to use a javascript 'show' operation for this
    		?>
    		<form method="post">
    		<input type='hidden' name='parent_id' value='<?=$arr['id']?>'>
    		<?=$indent?><label>Comment:<br>
    		<?=$indent?><textarea name="comment" rows="4" cols="50" placeholder="remember to be polite!"></textarea></label>
    		<input type="submit">
    		</form><br>
    		<?php
    		// recurse if there are children of the current parent
    		if(isset($data[$arr['id']]))
    		{
    			list_comments($arr['id'], $data, $level+1);
    		}
    	}
    } 
    
    // html
    ?>
    
    <?php
    // display any errors
    if(!empty($errors))
    {
    	echo implode('<br>',$errors);
    }
    ?>
    
    <?php
    // allow a comment on the main article
    ?>
    <form method="post">
    <input type='hidden' name='parent_id' value='0'>
    <label>Comment:<br>
    <textarea name="comment" rows="4" cols="50" placeholder="remember to be polite!"><?=$post['comment']??''?></textarea></label>
    <input type="submit">
    </form><br>
    
    <?php
    // list comments, starting with parent 0
    list_comments(0, $comment_data, 0);

     

    • Great Answer 1
  10. the code is probably redirecting around a couple of times, back to the form without any get parameters.

    based on the paths in the require statements in the two pieces of posted code, you either have multiple database.php files at different paths OR auth.php isn't just the 2nd piece of code you have posted and there's more to this than what has been posted? what's the full code for auth.php?

    next, by putting the form and the form processing code on different pages and accepting a get input that controls what message gets displayed, you have more code than is needed and you are opening up your site to a phishing attack, where someone can steal your user's login credentials on a copy of your site, then redirect them back to your site, making it look like they just mistyped a value.

    here's a laundry list of things you should/should not be doing -

    1. put the form processing and the form on the same page.
    2. don't attempt to detect if form field(s) are set to detect if the form has been submitted. if you had 30 or a 100 fields, would writing out isset() code using all those fields make sense? instead, just detect if a post method form was submitted. all the always-set fields will then be set.
    3. keep the form data as a set in an array variable, then operate on elements in this array variable throughout the rest of the code.
    4. forget you ever saw this validate() function. it can from bad code at w3schools, is misnamed, and the only thing it is doing 'properly' is to trim the data value.
    5. after you do item #3 on this list, you can trim all the data at once, using one single php statement.
    6. when you validate the input data, store user/validation errors in an array using the field name as the array index.
    7. after the end of all the validation logic, if the array holding the errors is empty, use the form data.
    8. use a prepared query when supplying external, unknown, dynamic values to an sql query when it gets executed to prevent any sql special characters from being able to break the sql syntax, which is how sql injection is accomplished. you would also want to switch to the much simpler PDO extension.
    9. don't store passwords as plain-text. use php's password_hash() and password_verify()
    10. list out the columns you are selecting in a query.
    11. if the query matches a row of data, you know that the WHERE clause was true. there's no good reason to compare in the php code the value(s) that were used in the WHERE clause. Don't Repeat Yourself (DRY.)
    12. the only value you should store in a session variable upon successful login is the user's id (autoincrement primary index.) you should query on each page request to get any other user information.
    13. upon successful completion of the post method form processing code, redirect to the exact same url of the current page to cause a get request for that page. this will prevent the browser from trying to resubmit the form data if the visitor reloads the page or navigates back to the page.
    14. if there are errors at step #7 in this list, the code will continue on to display the html document, display any errors in the errors array, redisplay the form, populating the appropriate form field values with the existing data.
    15. to get a form to submit to the same page it is on, simply leave out the entire action='...' attribute.
    16. any value you output on a web page needs to have htmlentities() applied to it to help prevent cross site scripting.

     

  11. 12 hours ago, Tekky said:

    in your example

    it's your example. all I did is show how to fetch, test, and loop over data to dynamically produce the <option> tags. the <form markup is just what you had in the starting code. i/we don't know what the intent is of having that form tag in the code. as to the rest of your statement, a description like that doesn't help. post an example showing what piece of data you have, what processing you want to do based on that piece of data, and what end result you want.

  12. is the following a true statement - you are picking an existing 'post' to edit via the $_GET['id'] input, and what you are showing us is the code that would allow the category(_id) to be changed? are you also editing other 'post' columns?

    next, you (will) have an issue if there are user/validation errors in the post method form processing code, in that you would want to initially populate the form field values with the existing data, then after the form has been submitted, populate the form field values with the submitted form data, so that the user doesn't need to keep reentering the changes over and over. the way to do this is to define an internal array variable that will initially receive the existing data, if the form has never been submitted (this internal array variable will be empty), then receives a trimmed working copy of the $_POST data inside the post method form processing code. this variable then gets used throughout the rest of the code.  an element in this array variable would be what gets used in the code setting the selected attribute for the category select/option menu. $post in SELECT ... FROM posts ... code is this variable.

    here's a laundry list of issues based on the snippets of code -

    1. there's no useful comments to help anyone looking at the code know what it is trying to do, i.e. what my first paragraph is asking.
    2. the $_GET['id'] input is a 'required' input for this page. if it isn't set, doesn't contain a integer > 0, or the SELECT query using it doesn't match a row of data, that's an application error. you should trim, then validate this input. if it isn't valid, setup and display a unique and helpful error message for each possible type of failure. only use it if it is valid, then if the query doesn't match a row of data, setup a unique and helpful error message for that and don't even display the edit form if there's no data to edit.
    3. i recommend that you pre-fetch any data from a SELECT query into an appropriately named php variable, then test/use that variable in the html document. you are doing this for the $post data. do the same for the category data. this will separate the different concerns in the code, making it easier to test, debug, and maintain the code.
    4. don't attempt to detect if the submit button is set. there are cases where it won't be. instead detect if a post method form was submitted. if there can be more than one set of post method form processing code on a page, use a hidden field with a unique value in it to control which set of form processing code to execute.
    5. ALL the post method form processing code needs to be inside the conditional statement that has detected if the form has been submitted.
    6. if the UPDATE query can result in duplicate data for columns that must be unique, you need error handling for that query that tests the error number and sets up a unique and helpful error message for any problem with the data values that were submitted.
    7. to get the form to submit to the same page it is on, leave the entire action='...' attribute out of the form tag.
    8. you should use the FILTER_VALIDATE... flags. not the FILTER_SANITIZE ... flags. you want to validate input data, not sanitize it. if it is not valid, repopulate the field with the value and let the user correct what is wrong with it. since you are not testing the return value from the filter_var() calls, you doesn't actually know if the test failed or not before using the values. the current code is using boolean false values when filter_var() fails, which can trigger sql data type errors, which is exactly what hackers want as feedback when they intentionally do things to trigger errors.
    9. you should also use prepared queries when supplying external, unknown, dynamic values to a query when it gets executed. you would also want to switch to the much simpler PDO extension. a prepared query, while only adding one php statement per query, when using the PDO extension, actually simplifies the sql query syntax and provides protection for all datatypes.

     

  13. php has a function that will help you build the query string part of urls, including urlencoding it - http_build_query. if you search the forum for that function you will find a number of examples showing how to get any existing $_GET parameters, populate the page parameter, build the query string, and build the pagination links.

  14. seems you are asking how to loop over the result from an sql query to dynamically produce a section of html markup?

    since you are using the PDO extension, i recommend that you fetch all the data from the query into an appropriately named php variable, then test and loop over that variable at the correct location in the html document -

    <?php
    
    // in the code querying for the data 
    $result_data = $stmt->fetchAll();
    
    
    // at the point of outputting the data
    if(empty($result_data))
    {
    	echo 'There is no data to display.';
    }
    else
    {?>
    	<form action="" method="get">
    	<label for="ListSaint">Choisis le Saint qui correspond a la date souhaité :</label>
    	<input list="ListSaints" name="ListSaint" id="ListSaint">
    	<datalist id="ListSaints">
    	<?php
    		foreach($result_data as $row)
    		{
    			echo "<option value='{$row['name']}'>";
    		}
    	?>
    	</datalist>
    	<input type="submit">
    	</form>
    <?php
    }
    ?>

     

    • Like 1
  15. the error is because you are using three different names for the same thing and you don't seem to be able to keep track of which name you are using. if the column in the database table is named customer_id, i recommend that you use that same name for that value throughout the code,  e.g. for the get parameter name (user_id), one unnecessarily copied  php variable name (id), another unnecessarily copied php variable name (customer_id), and the prepared query place-holder name (id). consistency and simplicity counts in programming, so you are not wasting time trying to keep track of three different names for the same thing.

    • Great Answer 1
  16. and this is how simple it is to use a prepared query with the PDO extension -

    // at the point of querying for and fetching the data
    $sql = "SELECT planets_name
                FROM planets p
                     JOIN
                     users u ON p.planets_starsystem = u.users_galaxyViewSystem
                WHERE planets_galaxy = ?
                AND planets_planet = ?
                AND users_id = ?
            ";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([ $testowanaGalaktyka, $testowanaPlaneta, $user_id ]);
    $result_data = $stmt->fetchAll();
    
    
    // at the point of outputting the data
    if(empty($result_data))
    {
    	echo 'There is no data to display.';
    }
    else
    {
    	foreach($result_data as $row)
    	{
    		echo $row['planets_name'].'<br>';
    	}
    }

     

  17. this is the same 'activity' as in your previous thread, just with different meaning columns.

    earlier thread -

    SELECT users_username
    FROM users u
    JOIN
    planets p ON u.users_id = p.planets_ownerid
    WHERE planets_galaxy = $testowanaGalaktyka
    AND planets_starsystem = $testowanySystem
    AND planets_planet = $testowanaPlaneta

    this thread -

    SELECT planets_name
    FROM planets p
    JOIN
    users u ON p.planets_starsystem = u.users_galaxyViewSystem
    WHERE planets_galaxy = $testowanaGalaktyka
    AND planets_planet = $testowanaPlaneta
    AND users_id = 1

    you are SELECTing things FROM a table JOINed with another table ON some condition relating the data between the tables WHERE some list of conditions that all ANDed together must be true. the learning to be had here is learning the structure of the query, so that you can write new queries based on what you have done before.

    the following is the SELECT query prototype definition, which is listed in the order that the parts must appear within a query, with the parts you are using in bold (note: FROM table_references includes any JOINs) -

    SELECT
        [ALL | DISTINCT | DISTINCTROW ]
        [HIGH_PRIORITY]
        [STRAIGHT_JOIN]
        [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
        [SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
        select_expr [, select_expr] ...
        [into_option]
        [FROM table_references
          [PARTITION partition_list]]
        [WHERE where_condition]
        [GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
        [HAVING where_condition]
        [WINDOW window_name AS (window_spec)
            [, window_name AS (window_spec)] ...]
        [ORDER BY {col_name | expr | position}
          [ASC | DESC], ... [WITH ROLLUP]]
        [LIMIT {[offset,] row_count | row_count OFFSET offset}]
        [into_option]
        [FOR {UPDATE | SHARE}
            [OF tbl_name [, tbl_name] ...]
            [NOWAIT | SKIP LOCKED]
          | LOCK IN SHARE MODE]
        [into_option]

    other common parts that you will see are - GROUP BY, occasionally HAVING, ORDER BY, and LIMIT. learning the meaning of and how to use these parts of a select query will allow you to write you own queries.

    note: most queries that will match more than one row should have an ORDER BY term so that the data will be in the order that you want it.

    next, you need to use a prepared query, with ? place-holders in the sql query for each value, then supply the actual values when the query is executed. this will prevent any sql special characters in a value from being able to break the sql query syntax, which is how sql injection is accomplished. since the mysqli extension is overly complicated when doing prepared queries, this would be a good time to switch to the much simpler and better designed PDO extension.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.