Jump to content
2020

Is This How To Display Results With mysqli_stmt_bind_result()

Recommended Posts

Posted (edited)

Folks,

 

I managed to get this piece of code working.

But I need you to check if it is buggy or in error or not.

I will add VALIDATION later. Just let me know is this how you query db with mysqli_stmt_bind_result (prepared statement using procedural style) and display results on screen ?

Don't worry about pagination. i will add that later. Just let me know if I got the basics correct or not to display results from db or not. That is all.

Note my comments in CAPITALS. They are questions to which I need answers.

conn.php

	<?php
	$db_server = 'localhost';
$db_user = 'root';
$db_password = '';
$db_database = 'test';
	$conn = mysqli_connect("$db_server","$db_user","","$db_database");
	//SHOULD I KEEP FOLLOWING 1 LINE INTACT HERE OR DUMP IT TO main file search.php ?
$conn->set_charset('utf8mb4');//Always use Charset.
//HOW TO CONVERT ABOVE LINE TPO PROCEDURAL ?
	if (!$conn)
{
    //HOW TO WRITE CODE SO FOLLOWING TECHNICAL ERROR IS WRITTEN TO ERROR FILE AND NOT SHOWN TO USER ?
    //Error Message to show user in technical/development mode to see errors.
    die("Database Error : " . mysqli_error($conn));
	    //Error Message to show User in Layman's mode to see errors.
    die("Database error.");
    exit();
}
	?>
	

Q1. Do not forget to answer my question you see in CAPITALS in above code (conn.php).

Check the search.php before replying.

 

error_reporting.php

	<?php
ini_set('error_reporting','E_ALL');
ini_set('display_errors','1');
ini_set('display_startup_errors','1');
error_reporting(E_ALL);
	//SHOULD I KEEP FOLLOWING 1 LINE INTACT HERE OR DUMP IT TO main file search.php ?
mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT);
?>
	

Q2. Do not forget to answer my question you see in CAPITALS in above code (error_reporting.php).

Check the search.php before replying.

 

 

 

search.php

	<?php
//include('error_reporting.php');
error_reporting(E_ALL);
ini_set('error_reporting',E_ALL);
ini_set('display_errors','1');
ini_set('display_startup_errors','1');
?>
	<form name = "search" method = "POST" action="">
<label for="keywords">Keywords:*</label>
<input type="text" name="keywords" id="keywords" placeholder="Input Keywords" required>
<br>
<button type="submit">Submit</button><br>
<button type="submit" value="submit">Submit</button><br>
<input type="submit" value="submit"><br>
<button name=submit value=" ">Search</button><br>
<button type="submit" name="submit" value="submit">Search</button>
<br>
<input type="reset">
<br>
</form>
	<?php
	if($_SERVER['REQUEST_METHOD'] === 'POST')
{
    if(ISSET($_POST['submit']))
    {
        if(ISSET($_POST['keywords']))
        {
            $keywords = $_POST['keywords'];
        }        
        
        //SHOULD I KEEP FOLLOWING 1 LINE INTACT HERE OR DUMP IT TO error_reporting.php ?
        mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT);        
        
        //SHOULD I KEEP FOLLOWING 5 LINES INTACT HERE OR DUMP IT TO conn.php ?
        $conn = mysqli_connect("localhost","root","","test");
        $conn->set_charset("utf8mb4");
        if(mysqli_connect_error())
        {
            echo "Could not connect!" . mysqli_connect_error();
        }
	        $query = "SELECT page_url,link_anchor_text,page_description,keyphrases,keywords FROM links WHERE keywords = ?";
	        $stmt = mysqli_stmt_init($conn);
	        //FIRST ATTEMPT TO DISPLAY TBL RESULTS USING mysqli_stmt_bind_result() FUNCTION. TEST RESULT: ATTEMPT A FAILURE!
        if(mysqli_stmt_prepare($stmt,$query))
        {
            mysqli_stmt_bind_param($stmt,'s',$keywords);
	            $stmt_execution = mysqli_stmt_execute($stmt);
            if($stmt_execution === FALSE)
            {
                printf("Error: %s.\n", mysqli_stmt_error($stmt));
                printf("Error: %d.\n", mysqli_stmt_errno($stmt));
                die;
            }
            
            $bind_result = mysqli_stmt_bind_result($stmt,$page_url,$link_anchor_text,$page_description,$keyphrase,$keywords);
            if($bind_result === FALSE)
            {
                printf("Error: %s.\n", mysqli_stmt_error($stmt));
                printf("Error: %d.\n", mysqli_stmt_errno($stmt));
                die;
            }
            
            $stmt_fetch = mysqli_stmt_fetch($stmt);
            if($stmt_fetch === FALSE)
            {
                printf("Error: %s.\n", mysqli_stmt_error($stmt));
                printf("Error: %d.\n", mysqli_stmt_errno($stmt));
                die;
            }
            
            while(mysqli_stmt_fetch($stmt))
            {
                echo "$page_url"; echo "<br>";
                echo "$link_anchor_text"; echo "<br>";
                echo "$page_description"; echo "<br>";
                echo "$keyphrase"; echo "<br>";
                echo "$keywords"; echo "<br>";
                echo "|";
                echo "<br>";
            }
            
            mysqli_stmt_close($stmt);
            mysqli_close($conn);
        }
        else
        {
            die("QUERY failed!)";
        }
	

 

Q3. Anything I should know ?

Edited by 2020

Share this post


Link to post
Share on other sites

this problem goes away if you switch to the much simpler and more consistent PDO extension, because you can fetch data from a PDO prepared query exactly the same way that you fetch it from a traditional, non-prepared query. a PDO prepared query also uses ? for the place-holders, so you can reuse your existing sql query syntax. all you have to do is make the connection using the PDO extension (setting the character set to match your database tables, set the error mode to exceptions, set emulated prepared queries to false, and set the default fetch mode to assoc), which i'm pretty sure has already been posted in some of your threads, but which someone would be willing to re0post, then change the remaining mysqli statements to the equivalent PDO statements, which you can do using by rote/A-B pattern matching. the statements needed for binding input and output parameters also go away. you simply supply an array of the input values to the execute([...]) call and use one of the fetch statements to retrieve the data.

3 hours ago, 2020 said:

Anything I should know ?

yes. you should be internalizing the meaning of the php, sql, html, and css statements/words you are using so that you know what they actually do, so that when you read or write code you know what each statement/word contributes to the 'story' on the web page. you basically need to become fluent enough in each of those languages so that you can write a meaningful and understandable short story using them. when i/we read code that someone posts, we start at the top and actually read the statements/words that have been posted, adding up what the meaning of each statement/word is contributing to the story being told. when we get to the end, if the statements/words all made sense and all have something to do with the task at hand, we know that the code will probably work (through testing will determine if it actually does.) when we see code that has all kinds of unnecessary, repetitive, missing, misused, and out of order statements/words, what do you think pops into our minds?

as to your posted code -

  1. you are no longer requiring (you should use 'require', not 'include', and both of these are not 'functions' so don't put ( ) around the filename) either the connection or the error .php files. Instead, you have attempted to insert the code into the main file,  introducing errors in the code and adding repetitive logic. why did you change this? did you miss the point about putting common code into a .php file and requiring it when needed?
  2. php's error related settings should be put into the php.ini on your system. this is so that they will report ALL php detected errors, even parse/syntax errors. this also allows your development system and your live/public server to be configured with their own error related settings and you don't need to remember to edit any code when moving it between those two systems.
  3. when you were initially and most lately given the mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); line, you were told and shown to put it before the line where you make the database connection. that would mean that it belongs in the conn.php file. if you had put it there and left it there, you wouldn't be mucking around with it now.
  4. you have also been told a number of times that when using exceptions for database statement errors, which is what the mysqli_report() line of code does, that none of the connection, query, prepare, and execute error handling logic will get executed upon an error and all that existing logic should be removed, simplifying and de-cluttering the code.
  5. you were also told that using exceptions for database statement errors and letting php catch and handle the exception, meaning there is no try/catch logic in your code, will cause database statement errors to 'automatically' get displayed/logged the same as php errors.  you are now asking in the conn.php code how to cause a connection error to get displayed/logged. you have been told how to do this. you also don't display these errors to the user/visitor to your site. you only display these errors to the programmer/developer, i.e. you, when you are learning, developing, and debugging code/query(ies.) you don't even tell the visitor, which could be a hacker, anything about an error that has occurred, since that will just encourage them to do more of the same things that caused the error in the first place.
  6. you are putting unnecessary double-quotes around php variables in the conn.php code. again, what do you think pops into our minds when we have to look at unnecessary things that could be causing a problem when someone asks us to look at their code?
  7. you have both a die() and an exit() statement in the conn.php code. that do the same thing. are you even looking at and reading your code?
  8. the search form should use method='get' (which is the default if you leave the method attribute out.) get is used when determine what will be displayed on a page. post is used when creating/altering data on the server or performing an action, such as sending an email.
  9. an empty action='' attribute is not valid html5. you were actually told to remove the entire action attribute.
  10. the search form should be 'sticky' and re-populate/select the form field values/choice(s) that correspond to any submitted data.
  11. only <input ... > or <button ... > tags that have a type='submit' attribute are capable of submitting the form. use one or the other, not both.
  12. only form elements with a name='...' attribute will be included in the submitted data.
  13. if you have only one post method form on a page, after you have tested the server REQUEST_METHOD, that's all the logic you need to start the form processing code.
  14. except for unchecked/unselected form elements, all other form fields will be set once the form has been submitted. using isset() around always-set form fields is a waste of your typing time.
  15. your form processing code should trim, then validate all inputs, storing any validation error messages in an array, using the field name as the array index. if after the end of the validation logic the array holding the error messages is empty, you can use the submitted form data.
  16. the get method 'business' logic, that knows how to get/produce the data needed to display the dynamic content on the page should come before the start of the html document. you would fetch all the data from any query into a php variable, then test/loop over that variable at the correct point in the html document.
  17. if you are going to continue to use the mysqli extension, just use the single $stmt = mysqli_prepare($conn,$query); statement, instead of $stmt = mysqli_stmt_init($conn); and mysqli_stmt_prepare($stmt,$query). i'm pretty sure you have been told this point before. i don't know why you are using the most complicated way of doing things.
  18. remember these two acronyms - Don't Repeat Yourself (DRY) and Keep It Simple stupid (KISS.) if you find yourself repeating the same code over and over or doing something in the most complicated way possible, you are probably doing something wrong.
  19. don't do this - if($bind_result === FALSE) the rest of the mysqli stmt error logic you have... the mysqli_stmt_bind_result() statement will produce a php error if it fails, which would be due to a programming mistake on your part. it won't produce a database statement error, and you won't get anything useful from the current code. the only things that produce database statement errors/error numbers are the connection, query, prepare, and execute statements.
  20. don't do this are well - if($stmt_fetch === FALSE) the rest of the mysqli stmt error logic you have... there's two problems with this - 1) your code is fetching the 1st row from the result set, but not displaying it, so you will be missing a row of data, and 2) a false value when you fetch data only means that there was no data to fetch. this is not an ERROR, it's how your code knows to stop fetching data. there won't be any mysqli statement error/error number values to display.
  21. php will destroy all resources when the script ends, so in most cases, you don't need to close a prepared query statement or close the database connection.

most of these things will actually simplify and clean up your code, leaving you with just the implementation logic that you should be concentrating on to get the application to work and the forum members will be more happy about looking at what you are posting since it won't contain a wall of unnecessary elements.

  • Thanks 1

Share this post


Link to post
Share on other sites
Posted (edited)

mac_gyver, what is the best code to put into php.ini to show all errors? When I'm coding, I put error_reporting(E_ALL), ini_set("display_errors", and include("file_with_errors.php"); on top of each page, but at least half the time I'll get a completely blank page because I did something stupid like echoed with a colon instead of semicolon. If there was something I could put in my php.ini file to show even THOSE types of errors, I'll buy you a beer.

p.s. I wish there was somebody in my dumb little town who could actually teach php to me from the ground up. I would sign up in a heartbeat. I can read 2020's code, and I can read my own code... but when I see code that Barand (or you) spits out, OMG, I cannot make heads nor tales of it. LIke that double underscore  __blah__  stuff. Or the "try" "do" stuff....

Edited by StevenOliver

Share this post


Link to post
Share on other sites

Hi Unique Idea Man, AKA UIman, AKA visiter52, aka 2020. After THREE years of us trying to teach you about Mysqli and coding under your various alt's across numerous forums, are we really right back at at the very beginning as though you have never seen this stuff?

Share this post


Link to post
Share on other sites

I actually thought 2020 was the "Hi Friends" guy that got banned about a year ago. He wouldn't even wait a full day before asking the same questions, like he never read the answers. At least I READ the answers.... My problem is I get sidetracked.... For example, a few days ago I was trying to learn how only have one redirect no matter what... and now I have 30 browser windows open trying to learn regex..... and in doing so, I'm learning preg_match, where the answer is contained in an array, and now I realize my Array knowledge is ZERO..... I really wish I could start at the beginning, and learn PHP from the ground up and MASTER something before I die....

Share this post


Link to post
Share on other sites
15 minutes ago, StevenOliver said:

mac_gyver, what is the best code to put into php.ini to show all errors?

they are settings actually - name = value

error_reporting = E_ALL (or even better, a -1 to future proof it, as the E_ALL value can have more added to it)

display_errors = on

another setting to change, since it is probably off on a live/public server and you may not be able to set it there, is -

output_buffering = off

the runtime issue with putting these settings into your code is that if the code contains a parse/syntax error, the code where these settings are at never runs to cause the settings to take effect.

Share this post


Link to post
Share on other sites

Okay good, I just now tried that. Now I'm seeing every error. Thank you!

Also, I never thought of having output_buffering off -- I am glad you pointed that out. Maybe that's the issue I've had the most in the past.

One thing I found -- sometimes when I have error reporting turned on with all errors, I sometimes get lazy in coding. like, I'll type anything and wait for the error.... type something else and watch the error 😀 ... But when I have error reporting OFF, it makes me concentrate more on typing correctly because nothing is more annoying than the "blank page".

Share this post


Link to post
Share on other sites
On 7/18/2020 at 9:35 AM, benanamen said:

Hi Unique Idea Man, AKA UIman, AKA visiter52, aka 2020. After THREE years of us trying to teach you about Mysqli and coding under your various alt's across numerous forums, are we really right back at at the very beginning as though you have never seen this stuff?

visiter52 ? I'm not born in 1952. Not even my dad!

I thought you'll never figure it out this time but I guess I was wrong! What was the name of that other British forum where you and that Brit mate of your's ganged up against me simply because I asked the same questions across 10 forums to get tonnes of opinions for my learning purose since all programmers don't answer equal ? What was his username TJ or whatever. The whining guy. He was helpful though originally but at the end I put up with more of his whining than anything else and he started getting on my nerves. I must try my luck at that forum again if Requinix or Mac Guyver ban me again from here. ;)  I think I got banned twice from here without any explanation why. Guessing you were behind it. As usual. Backbiting.

At sitepoint.com they somehow figure me out and ban me till year 3000. Lol! Probably got banned thrice there thanks to you.

Well, I'm glad Requinix has figured me out and hasn't banned me a 2nd or 3rd time here now. :) Just got to make sure not to open more than one thread at a time. That was his or her warning just now.

As for Mac Guyver, he didn't figure me out this time. Look all the reponses he has given to this new Username of mine. :). I think it was him, and not requinix, who banned me the first time. Nice to respond to someone you banned once bfore. Right ? ;)

Yes, I have been promising you to jump into pdo since 2015 but I get side tracked. Still struggling with mysqli.

I've been banned from many forums. Most of them don't even tell me why. I'm guessing you were behind them since you made it very clear you went around a few forums and grassed me up. Going round and telling them I've got duplicate threads in other forums. Nowadays, I don't duplicate threads in 10-20 forums anymore.  Thanks to you I got banned from them and so no chances of me creating duplicate threads on 10 forums anymore. And even if I do create a duplicate thread, then I make sure the wordings are a little different and the titles are different too so you can't google and spot them. ;)

Btw, I get lucky at StackOverFlow from time to time when forums like this respond less or are unable to help because they don't know the answers or too busy too help. But I don't frequent there too much. The'yre too strict when it comes to how we ask questions. And when one account tells me I have reached my questioning limit and keep showing me the same silly message even after a month, I just open another account. And get questioning. ;)

And I think Requinix banned me from 2-3 forums. Well, he/she won't be doing that no more since he/she only in this forum nowadays. But there is one forum I've never been banned from within the last 3-5 yrs. Go and figure which one that is! And you Benanamen are not there. Lol!

But I get my questions answered here more frequently recently and so I'm staying here for the time being until I've learnt everything basic about errors, and exceptions and the whole lot from Mac Guyver and Barand. And maybe from Requinix, if I get lucky! ;)

As of now, I just finished reading Mac Guyver's long post. A lot to digest. A lot I didn't understand. I'm busy now tryign to fix my code based on his reply.

Also, I came across this just now:

https://www.evidentlycube.com/blog/disappearing-error-message-in-mysqli

Googled: mysqli_stmt_error()

Trying to see if I can integrate my codes around it. A bit too much for me to handle though. A bit over my league.

Giving the links here, incase it teaches others here a thing or two. :)

Share this post


Link to post
Share on other sites
Posted (edited)
On 7/18/2020 at 9:42 AM, StevenOliver said:

I actually thought 2020 was the "Hi Friends" guy that got banned about a year ago. He wouldn't even wait a full day before asking the same questions, like he never read the answers. At least I READ the answers.... My problem is I get sidetracked.... For example, a few days ago I was trying to learn how only have one redirect no matter what... and now I have 30 browser windows open trying to learn regex..... and in doing so, I'm learning preg_match, where the answer is contained in an array, and now I realize my Array knowledge is ZERO..... I really wish I could start at the beginning, and learn PHP from the ground up and MASTER something before I die....

Why did it make you think I was "Hi Friends" ? Who is he/she and from which forum ?

If you must know, which Benanamen knows as I told him once but he still keeps forgetting, my usernames are usually based around the forum's name. If you want to know why Benanamen hates me, google for: "Uniqueideaman". You won;t find me misbehaving in any forum. It's just I used to program (learn) every night. When I came across an obstacle, I first opened a thread in some forum. Sometimes I got answered immediately or on the same day. Sometimes I had to wait a day or 3. At the end, I realized the wait was a waste of my learning time and so I got impatient and did not open a thread at one forum only. Opened the same thread on 10. Then saw which forums answered within the day or within the hour.

I saw, I got a variety of answers as some programmers knew one thing that others didn't. I then found myself in a position to test all their answers out and figure-out which programmers were strong in which field. I then stuck to the programmers I thought were best in their fields.

Benanamen didn't like this. He thought I was wasting programmers' times across many forums asking the same questions everywhere. Those programmers didn't think like him. They saw it as me contributing to their forums. The same questions and their answers were benefiting their forum members. For example, I open a thread and ask a question here. I get answered here. How does that help the other 9 forums and their members ? If I open the same threads over there too then those 9 other threads at 9 other forums yield answers respectively from their senior members based on my questions and newcomers (like me) over there benefit from my questions and the answers there. That is why some forums did not ban me, even though our little from "Mr Benanamen" was winding them up and pestering them to ban me.

I might find myself banned for writing this post. But hey, a person has the right to be heard why he did things the way he/she did.

And if you really must know. Here is the top secret. I think Benanamen got on my tail because I once told him I can't remember his Username and asked him if I can call him "Banan Man" to which he went off his head. From then on, I became his soul enemy. But that didn't stop him from answering my threads though. ;)

Anyway, I like it when you respond to my threads. Don't let Benanamen put you off.

Oh, I just remembered. Another time I asked Benamen, if I can call him "Benny Hill" and that made things worst between us. Lol!

Youtube for "British Sitcom: Benny Hill".

Lol!

I'm sure, once I jump into pdo and open threads based on it then "Ben" would be the first to answer as pdo is his speciality.

 

Edited by 2020

Share this post


Link to post
Share on other sites
Posted (edited)
On 7/18/2020 at 8:35 AM, mac_gyver said:

this problem goes away if you switch to the much simpler and more consistent PDO extension, because you can fetch data from a PDO prepared query exactly the same way that you fetch it from a traditional, non-prepared query. a PDO prepared query also uses ? for the place-holders, so you can reuse your existing sql query syntax. all you have to do is make the connection using the PDO extension (setting the character set to match your database tables, set the error mode to exceptions, set emulated prepared queries to false, and set the default fetch mode to assoc), which i'm pretty sure has already been posted in some of your threads, but which someone would be willing to re0post, then change the remaining mysqli statements to the equivalent PDO statements, which you can do using by rote/A-B pattern matching. the statements needed for binding input and output parameters also go away. you simply supply an array of the input values to the execute([...]) call and use one of the fetch statements to retrieve the data.

yes. you should be internalizing the meaning of the php, sql, html, and css statements/words you are using so that you know what they actually do, so that when you read or write code you know what each statement/word contributes to the 'story' on the web page. you basically need to become fluent enough in each of those languages so that you can write a meaningful and understandable short story using them. when i/we read code that someone posts, we start at the top and actually read the statements/words that have been posted, adding up what the meaning of each statement/word is contributing to the story being told. when we get to the end, if the statements/words all made sense and all have something to do with the task at hand, we know that the code will probably work (through testing will determine if it actually does.) when we see code that has all kinds of unnecessary, repetitive, missing, misused, and out of order statements/words, what do you think pops into our minds?

as to your posted code -

  1. you are no longer requiring (you should use 'require', not 'include', and both of these are not 'functions' so don't put ( ) around the filename) either the connection or the error .php files. Instead, you have attempted to insert the code into the main file,  introducing errors in the code and adding repetitive logic. why did you change this? did you miss the point about putting common code into a .php file and requiring it when needed?
  2. php's error related settings should be put into the php.ini on your system. this is so that they will report ALL php detected errors, even parse/syntax errors. this also allows your development system and your live/public server to be configured with their own error related settings and you don't need to remember to edit any code when moving it between those two systems.
  3. when you were initially and most lately given the mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); line, you were told and shown to put it before the line where you make the database connection. that would mean that it belongs in the conn.php file. if you had put it there and left it there, you wouldn't be mucking around with it now.
  4. you have also been told a number of times that when using exceptions for database statement errors, which is what the mysqli_report() line of code does, that none of the connection, query, prepare, and execute error handling logic will get executed upon an error and all that existing logic should be removed, simplifying and de-cluttering the code.
  5. you were also told that using exceptions for database statement errors and letting php catch and handle the exception, meaning there is no try/catch logic in your code, will cause database statement errors to 'automatically' get displayed/logged the same as php errors.  you are now asking in the conn.php code how to cause a connection error to get displayed/logged. you have been told how to do this. you also don't display these errors to the user/visitor to your site. you only display these errors to the programmer/developer, i.e. you, when you are learning, developing, and debugging code/query(ies.) you don't even tell the visitor, which could be a hacker, anything about an error that has occurred, since that will just encourage them to do more of the same things that caused the error in the first place.
  6. you are putting unnecessary double-quotes around php variables in the conn.php code. again, what do you think pops into our minds when we have to look at unnecessary things that could be causing a problem when someone asks us to look at their code?
  7. you have both a die() and an exit() statement in the conn.php code. that do the same thing. are you even looking at and reading your code?
  8. the search form should use method='get' (which is the default if you leave the method attribute out.) get is used when determine what will be displayed on a page. post is used when creating/altering data on the server or performing an action, such as sending an email.
  9. an empty action='' attribute is not valid html5. you were actually told to remove the entire action attribute.
  10. the search form should be 'sticky' and re-populate/select the form field values/choice(s) that correspond to any submitted data.
  11. only <input ... > or <button ... > tags that have a type='submit' attribute are capable of submitting the form. use one or the other, not both.
  12. only form elements with a name='...' attribute will be included in the submitted data.
  13. if you have only one post method form on a page, after you have tested the server REQUEST_METHOD, that's all the logic you need to start the form processing code.
  14. except for unchecked/unselected form elements, all other form fields will be set once the form has been submitted. using isset() around always-set form fields is a waste of your typing time.
  15. your form processing code should trim, then validate all inputs, storing any validation error messages in an array, using the field name as the array index. if after the end of the validation logic the array holding the error messages is empty, you can use the submitted form data.
  16. the get method 'business' logic, that knows how to get/produce the data needed to display the dynamic content on the page should come before the start of the html document. you would fetch all the data from any query into a php variable, then test/loop over that variable at the correct point in the html document.
  17. if you are going to continue to use the mysqli extension, just use the single $stmt = mysqli_prepare($conn,$query); statement, instead of $stmt = mysqli_stmt_init($conn); and mysqli_stmt_prepare($stmt,$query). i'm pretty sure you have been told this point before. i don't know why you are using the most complicated way of doing things.
  18. remember these two acronyms - Don't Repeat Yourself (DRY) and Keep It Simple stupid (KISS.) if you find yourself repeating the same code over and over or doing something in the most complicated way possible, you are probably doing something wrong.
  19. don't do this - if($bind_result === FALSE) the rest of the mysqli stmt error logic you have... the mysqli_stmt_bind_result() statement will produce a php error if it fails, which would be due to a programming mistake on your part. it won't produce a database statement error, and you won't get anything useful from the current code. the only things that produce database statement errors/error numbers are the connection, query, prepare, and execute statements.
  20. don't do this are well - if($stmt_fetch === FALSE) the rest of the mysqli stmt error logic you have... there's two problems with this - 1) your code is fetching the 1st row from the result set, but not displaying it, so you will be missing a row of data, and 2) a false value when you fetch data only means that there was no data to fetch. this is not an ERROR, it's how your code knows to stop fetching data. there won't be any mysqli statement error/error number values to display.
  21. php will destroy all resources when the script ends, so in most cases, you don't need to close a prepared query statement or close the database connection.

most of these things will actually simplify and clean up your code, leaving you with just the implementation logic that you should be concentrating on to get the application to work and the forum members will be more happy about looking at what you are posting since it won't contain a wall of unnecessary elements.

Let me see Mac Guyver, if I understood you correctly.

1. you are no longer requiring (you should use 'require', not 'include', and both of these are not 'functions' so don't put ( ) around the filename) either the connection or the error .php files. Instead, you have attempted to insert the code into the main file,  introducing errors in the code and adding repetitive logic. why did you change this? did you miss the point about putting common code into a .php file and requiring it when needed?

You said this is incorrect:

include('conn.php');

So now I changed it to:

include 'conn.php';

I googled and saw you correct. I don't know why I did it the way I did. Must have picked-up the error from some programmer's sample code and stuck to it for 3yrs. Thanks for bringing this to my attention.

 

2. php's error related settings should be put into the php.ini on your system. this is so that they will report ALL php detected errors, even parse/syntax errors. this also allows your development system and your live/public server to be configured with their own error related settings and you don't need to remember to edit any code when moving it between those two systems.

You mean, I should not have an error_reporting.php that I require from all file like so ? ....

require 'error_reporting.php';

So, all my error_reporting.php contents should be in the .ini file instead ? All the following should be in it ?

	<?php
ini_set('error_reporting','E_ALL');
ini_set('display_errors','1');
ini_set('display_startup_errors','1');
error_reporting(E_ALL);
	

As of now, I got no experience with .ini and so I'm sticking the way I am doing it while on DEV mode. Once I switch over to PRODUCTION mode and have fixed the basics, then I'll get learning about .ini file as that stuff is adv stuff. Thanks for the advice.

 

3.when you were initially and most lately given the mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); line, you were told and shown to put it before the line where you make the database connection. that would mean that it belongs in the conn.php file. if you had put it there and left it there, you wouldn't be mucking around with it now.

Fixed it! Thanks!

 

4. you have also been told a number of times that when using exceptions for database statement errors, which is what the mysqli_report() line of code does, that none of the connection, query, prepare, and execute error handling logic will get executed upon an error and all that existing logic should be removed, simplifying and de-cluttering the code.

Ooops! I forgot. remember, EXCEPTION and the whole bunch I am not really familiar with and so will make mistakes on those fields.

So, I should change this ...

	mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT);        
        
       $query = "SELECT page_url,link_anchor_text,page_description,keyphrases,keywords FROM links WHERE keywords = ?";
	        $stmt = mysqli_stmt_init($conn);
	        if(mysqli_stmt_prepare($stmt,$query))
        {
            mysqli_stmt_bind_param($stmt,'s',$keywords);
	            $stmt_execution = mysqli_stmt_execute($stmt);
            if($stmt_execution === FALSE)
            {
                printf("Error: %s.\n", mysqli_stmt_error($stmt));
                printf("Error: %d.\n", mysqli_stmt_errno($stmt));
                die;
            }
	

 

to either this:

 

A).

	       $query = "SELECT page_url,link_anchor_text,page_description,keyphrases,keywords FROM links WHERE keywords = ?";
	        $stmt = mysqli_stmt_init($conn);
	         if(mysqli_stmt_prepare($stmt,$query))
        {
            mysqli_stmt_bind_param($stmt,'s',$keywords);
	            $stmt_execution = mysqli_stmt_execute($stmt);
            if($stmt_execution === FALSE)
            {
                printf("Error: %s.\n", mysqli_stmt_error($stmt));
                printf("Error: %d.\n", mysqli_stmt_errno($stmt));
                die;
            }
	

 

or to this ....

	mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT);        
        
        $conn = mysqli_connect("localhost","root","","test");
        $conn->set_charset("utf8mb4");
        if(mysqli_connect_error())
        {
            echo "Could not connect!" . mysqli_connect_error();
        }
	        $query = "SELECT page_url,link_anchor_text,page_description,keyphrases,keywords FROM links WHERE keywords = ?";
	        $stmt = mysqli_stmt_init($conn);
	        if(mysqli_stmt_prepare($stmt,$query))
        {
            mysqli_stmt_bind_param($stmt,'s',$keywords);
	            $stmt_execution = mysqli_stmt_execute($stmt);
            if($stmt_execution === FALSE)
	

Which one would you use ? A) or B) ? And why that one over the other ?

 

6. you are putting unnecessary double-quotes around php variables in the conn.php code. again, what do you think pops into our minds when we have to look at unnecessary things that could be causing a problem when someone asks us to look at their code?

Ok. Fixed this:

	$conn = mysqli_connect("$db_server","$db_user,""","$db_database");
	

to this:

	$conn = mysqli_connect($db_server,$db_user,,$db_database);
	

Or should i do it like this instead for the "no password" ?

	$conn = mysqli_connect($db_server,$db_user,' ',$db_database);//single quote for the blank password
	

Or maybe this ?

	$conn = mysqli_connect($db_server,$db_user," ",$db_database); dbl quote for the blank password
	

 

7.

you have both a die() and an exit() statement in the conn.php code. that do the same thing. are you even looking at and reading your code?

I changed the code many times by adding and subtracting. When the die() didn't exist the exit() did. When i added the die() I overlooked the exit(), I guess. That is what happens when you rush things, I guess.

Thanks for bringing this to my attention.

 

8. the search form should use method='get' (which is the default if you leave the method attribute out.) get is used when determine what will be displayed on a page. post is used when creating/altering data on the server or performing an action, such as sending an email.

I do get the pic that you prefer method=GET over POST and I did get your message the first time. But, unless I am totally in the "wrong learning" about the POST method (my weak subject), I did not use the method=GET simply because I am not passing any variable as params in the url where I would make use of the $_GET to extract them out of the url.

So, if you click the submit button on the form and your inputs get directly posted to the server without your inputs getting passed onto the url as params then should I not be using the method=POST especially when I am grabbing your inputs via the $_POST ?

I am confused now. Scratching my head.

 

9. an empty action='' attribute is not valid html5. you were actually told to remove the entire action attribute.

About 2 programmers told me to do it like this (the way I did) in another 1 or 2 forums on another project (I think). Now you understand why I used to ask the same questions or open the same thread in different forums ? To get different opinions from different programmers from different walks of life. Had I stuck to those forums and never asked the same topic here then how on earth would you have told me this here thus bringing to my attention the serious flaw ? I can now go to those other forums and teach them what you taught me. It's called "sharing knowledge across the internet. Which Mr Benanamen never really understands/ I'm afraid!".

 

10. the search form should be 'sticky' and re-populate/select the form field values/choice(s) that correspond to any submitted data.

Sorry! I don't understand. Care to show me an example ?

In the past, I built submit forms where if the user submitted the form and had input errors then the page would reload giving error and the user's input would be auto typed back into the input fields so user does not have to retype those fields again where he made no input errors. But all that was in submit forms. Not search forms.

Are you talking about search forms like google ? Where when you make a keyword search and SERP shows you page 1 then when you click page 2 then the search form on page 2 retypes your keywords on the search box present on serp page 2 ? Don't worry, I know how to do that. Those are stage 2. I am still at stage 1, the basics, remember ? I am getting you to check stage 1 before I jump into stage 2. I did say, you lot are checking out the basic parts of my code/project. Didn't I ?

But if you meant something else then by all means be my guest and clarify a bit more to clear the misunderstanding.

 

Edited by 2020

Share this post


Link to post
Share on other sites

Mac Guyver,

If you don't mind me asking, show us a simple EXCEPTION, TRY & CATCH on 2 prepared statements.

The 2 prepared statements should be for these mysql queries:

1. INSERT query

2. SELECT query

 

From your examples, we will learn. After that, it shouldn't be too hard for me to do likewise for DELETE, UPDATE queries.

Once I got the hang of things from your example, then I should not be making these mistakes again. And you won't have to repeat yourself either to me or someone else as your reply code sample should be enough to teach the newbies.

 

Thanks

 

if Mac guyver's busy then Barand, Requinix and even others are welcome to chime in.

 

Share this post


Link to post
Share on other sites
Posted (edited)
On 7/18/2020 at 8:35 AM, mac_gyver said:

this problem goes away if you switch to the much simpler and more consistent PDO extension, because you can fetch data from a PDO prepared query exactly the same way that you fetch it from a traditional, non-prepared query. a PDO prepared query also uses ? for the place-holders, so you can reuse your existing sql query syntax. all you have to do is make the connection using the PDO extension (setting the character set to match your database tables, set the error mode to exceptions, set emulated prepared queries to false, and set the default fetch mode to assoc), which i'm pretty sure has already been posted in some of your threads, but which someone would be willing to re0post, then change the remaining mysqli statements to the equivalent PDO statements, which you can do using by rote/A-B pattern matching. the statements needed for binding input and output parameters also go away. you simply supply an array of the input values to the execute([...]) call and use one of the fetch statements to retrieve the data.

yes. you should be internalizing the meaning of the php, sql, html, and css statements/words you are using so that you know what they actually do, so that when you read or write code you know what each statement/word contributes to the 'story' on the web page. you basically need to become fluent enough in each of those languages so that you can write a meaningful and understandable short story using them. when i/we read code that someone posts, we start at the top and actually read the statements/words that have been posted, adding up what the meaning of each statement/word is contributing to the story being told. when we get to the end, if the statements/words all made sense and all have something to do with the task at hand, we know that the code will probably work (through testing will determine if it actually does.) when we see code that has all kinds of unnecessary, repetitive, missing, misused, and out of order statements/words, what do you think pops into our minds?

as to your posted code -

  1. you are no longer requiring (you should use 'require', not 'include', and both of these are not 'functions' so don't put ( ) around the filename) either the connection or the error .php files. Instead, you have attempted to insert the code into the main file,  introducing errors in the code and adding repetitive logic. why did you change this? did you miss the point about putting common code into a .php file and requiring it when needed?
  2. php's error related settings should be put into the php.ini on your system. this is so that they will report ALL php detected errors, even parse/syntax errors. this also allows your development system and your live/public server to be configured with their own error related settings and you don't need to remember to edit any code when moving it between those two systems.
  3. when you were initially and most lately given the mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); line, you were told and shown to put it before the line where you make the database connection. that would mean that it belongs in the conn.php file. if you had put it there and left it there, you wouldn't be mucking around with it now.
  4. you have also been told a number of times that when using exceptions for database statement errors, which is what the mysqli_report() line of code does, that none of the connection, query, prepare, and execute error handling logic will get executed upon an error and all that existing logic should be removed, simplifying and de-cluttering the code.
  5. you were also told that using exceptions for database statement errors and letting php catch and handle the exception, meaning there is no try/catch logic in your code, will cause database statement errors to 'automatically' get displayed/logged the same as php errors.  you are now asking in the conn.php code how to cause a connection error to get displayed/logged. you have been told how to do this. you also don't display these errors to the user/visitor to your site. you only display these errors to the programmer/developer, i.e. you, when you are learning, developing, and debugging code/query(ies.) you don't even tell the visitor, which could be a hacker, anything about an error that has occurred, since that will just encourage them to do more of the same things that caused the error in the first place.
  6. you are putting unnecessary double-quotes around php variables in the conn.php code. again, what do you think pops into our minds when we have to look at unnecessary things that could be causing a problem when someone asks us to look at their code?
  7. you have both a die() and an exit() statement in the conn.php code. that do the same thing. are you even looking at and reading your code?
  8. the search form should use method='get' (which is the default if you leave the method attribute out.) get is used when determine what will be displayed on a page. post is used when creating/altering data on the server or performing an action, such as sending an email.
  9. an empty action='' attribute is not valid html5. you were actually told to remove the entire action attribute.
  10. the search form should be 'sticky' and re-populate/select the form field values/choice(s) that correspond to any submitted data.
  11. only <input ... > or <button ... > tags that have a type='submit' attribute are capable of submitting the form. use one or the other, not both.
  12. only form elements with a name='...' attribute will be included in the submitted data.
  13. if you have only one post method form on a page, after you have tested the server REQUEST_METHOD, that's all the logic you need to start the form processing code.
  14. except for unchecked/unselected form elements, all other form fields will be set once the form has been submitted. using isset() around always-set form fields is a waste of your typing time.
  15. your form processing code should trim, then validate all inputs, storing any validation error messages in an array, using the field name as the array index. if after the end of the validation logic the array holding the error messages is empty, you can use the submitted form data.
  16. the get method 'business' logic, that knows how to get/produce the data needed to display the dynamic content on the page should come before the start of the html document. you would fetch all the data from any query into a php variable, then test/loop over that variable at the correct point in the html document.
  17. if you are going to continue to use the mysqli extension, just use the single $stmt = mysqli_prepare($conn,$query); statement, instead of $stmt = mysqli_stmt_init($conn); and mysqli_stmt_prepare($stmt,$query). i'm pretty sure you have been told this point before. i don't know why you are using the most complicated way of doing things.
  18. remember these two acronyms - Don't Repeat Yourself (DRY) and Keep It Simple stupid (KISS.) if you find yourself repeating the same code over and over or doing something in the most complicated way possible, you are probably doing something wrong.
  19. don't do this - if($bind_result === FALSE) the rest of the mysqli stmt error logic you have... the mysqli_stmt_bind_result() statement will produce a php error if it fails, which would be due to a programming mistake on your part. it won't produce a database statement error, and you won't get anything useful from the current code. the only things that produce database statement errors/error numbers are the connection, query, prepare, and execute statements.
  20. don't do this are well - if($stmt_fetch === FALSE) the rest of the mysqli stmt error logic you have... there's two problems with this - 1) your code is fetching the 1st row from the result set, but not displaying it, so you will be missing a row of data, and 2) a false value when you fetch data only means that there was no data to fetch. this is not an ERROR, it's how your code knows to stop fetching data. there won't be any mysqli statement error/error number values to display.
  21. php will destroy all resources when the script ends, so in most cases, you don't need to close a prepared query statement or close the database connection.

most of these things will actually simplify and clean up your code, leaving you with just the implementation logic that you should be concentrating on to get the application to work and the forum members will be more happy about looking at what you are posting since it won't contain a wall of unnecessary elements.

11. only <input ... > or <button ... > tags that have a type='submit' attribute are capable of submitting the form. use one or the other, not both.

I was supposed to weed-out the 4 buttons for 1. I forgot to do it.

Anyway, the first 3 weren't working. Only the latter 2.

Which one you recommend out of these working 2 ?

	<button name=submit value=" ">Search</button><br>
<button type="submit" name="submit" value="submit">Search</button>
	

 

12. only form elements with a name='...' attribute will be included in the submitted data.

Meaning, if the data sending part is like this:

name="mac_guyver"

then the data recieving part is like this (the $_POST should be):

$_POST['mac_guyver'];

Correct ?

 

13. if you have only one post method form on a page, after you have tested the server REQUEST_METHOD, that's all the logic you need to start the form processing code.

Meaning, it should not have been like this:

	if($_SERVER['REQUEST_METHOD'] === 'POST')
{
    if(ISSET($_POST['submit']))
    {
	

But should have been:

if($_SERVER['REQUEST_METHOD'] === 'POST')
{

I did it like this beacause there will be more than one button on page. Like one for Login, one for reg, one for Search.

php has to detect which button got clicked. And so, put the button's name on the 2nd IF. Did I not do it correct ?

 

14. except for unchecked/unselected form elements, all other form fields will be set once the form has been submitted. using isset() around always-set form fields is a waste of your typing time.

Meaning, I should never check for button clicks or form inputs like this:

if(ISSET($_POST['submit']))

 

if(ISSET($_POST['first_name']))

Quite frankly Mac, that's how I did things but then programmer's at forums plus tutorials show to check user inputs and button clicks with the ISSET. So you now suggesting it is extra bits of code that i should do without ?

 

15. your form processing code should trim, then validate all inputs, storing any validation error messages in an array, using the field name as the array index. if after the end of the validation logic the array holding the error messages is empty, you can use the submitted form data.

I asked you in another thread to show me how to do this with the error array thing as I have not a clue how to do it and I have not come across any tutorials lately that shows how to do it. And so, how about showing us how to do it ? Show a typical example.

 

16. he get method 'business' logic, that knows how to get/produce the data needed to display the dynamic content on the page should come before the start of the html document. you would fetch all the data from any query into a php variable, then test/loop over that variable at the correct point in the html document.

In other words, the html should be at the bottom and the php at the top ?

 

17. if you are going to continue to use the mysqli extension, just use the single $stmt = mysqli_prepare($conn,$query); statement, instead of $stmt = mysqli_stmt_init($conn); and mysqli_stmt_prepare($stmt,$query). i'm pretty sure you have been told this point before. i don't know why you are using the most complicated way of doing things.

I explained why I did this. Sticking to long version as of now in this project. Can return back to your short or alias version in upcoming projects. Ok ?

 

18. remember these two acronyms - Don't Repeat Yourself (DRY) and Keep It Simple stupid (KISS.) if you find yourself repeating the same code over and over or doing something in the most complicated way possible, you are probably doing something wrong.

I did to an extreme level on a project on hold. I will re-open that project and wonder you with it!

 

19. don't do this - if($bind_result === FALSE) the rest of the mysqli stmt error logic you have... the mysqli_stmt_bind_result() statement will produce a php error if it fails, which would be due to a programming mistake on your part. it won't produce a database statement error, and you won't get anything useful from the current code. the only things that produce database statement errors/error numbers are the connection, query, prepare, and execute statements.

I knew errors only get shown on mysql queries, mysql connections and php syntax errors. But then I come across errors on mysqli_prepare() and so I thought maybe there is one for mysql_stmt_bind_result() that I can build for php to check if the result were bound or not. Are you saying, php is unable to check if anything got bound or not but it is able to check if anything got prepared or not ?

 

20. don't do this are well - if($stmt_fetch === FALSE) the rest of the mysqli stmt error logic you have... there's two problems with this - 1) your code is fetching the 1st row from the result set, but not displaying it, so you will be missing a row of data, and 2) a false value when you fetch data only means that there was no data to fetch. this is not an ERROR, it's how your code knows to stop fetching data. there won't be any mysqli statement error/error number values to display.

So the statement class (if that is what they call it), on it you can only get php show errors for $stmt->execute/mysqli_stmt_execute($stmt) and nothing else such as these:

	mysqli_stmt_bind_result($stmt) 
	

 

	mysqli_stmt_get_result($stmt) 
	

 

	mysqli_stmt_fetch_all($stmt) 
	

 

	mysqli_stmt_fetch($stmt) 
	

 

etc. ?

 

20. php will destroy all resources when the script ends, so in most cases, you don't need to close a prepared query statement or close the database connection.

 

So, why they teach in tutorials including php manual to close connections and statements then ?

https://www.php.net/manual/en/mysqli-stmt.prepare.php

https://www.tutorialrepublic.com/php-tutorial/php-mysql-prepared-statements.php

https://www.w3schools.com/php/func_mysqli_prepare.asp

 

Not arguing with you on this one. Just curious to know the answer. That is all.

 

Edited by 2020

Share this post


Link to post
Share on other sites
Posted (edited)

@mac_guyver,

 

If I got this:

	while(mysqli_stmt_fetch($stmt))
            {
                echo "$page_url"; echo "<br>";
                echo "$link_anchor_text"; echo "<br>";
                echo "$page_description"; echo "<br>";
                echo "$keyphrase"; echo "<br>";
                echo "$keywords"; echo "<br>";
                echo "|";
                echo "<br>";
            }
	

 

then I don't need this before the loop. Right ?

	$stmt_fetch = mysqli_stmt_fetch($stmt);
	

 

Yes or no ?

What happens if I have both and what happens if I have just the loop ?

I know if I have just the one without the loop then I am shown row[0]. Right ?

Edited by 2020

Share this post


Link to post
Share on other sites

@mac_guyver,

based on your advices, this is now what my notes look like. Did I get them correct or not ?

	<?php
include 'error_reporting.php';
error_reporting(E_ALL);
ini_set('error_reporting',E_ALL);
ini_set('display_errors','1');
ini_set('display_startup_errors','1');
	
if($_SERVER['REQUEST_METHOD'] === 'POST')
{
    if(ISSET($_POST['submit']))
    {
        if(ISSET($_POST['keywords']))
        {
            $keywords = $_POST['keywords'];
        }        
        
        $query = "SELECT page_url,link_anchor_text,page_description,keyphrases,keywords FROM links WHERE keywords = ?";
	        $stmt = mysqli_stmt_init($conn);
	        if(mysqli_stmt_prepare($stmt,$query))
        {
            mysqli_stmt_bind_param($stmt,'s',$keywords);
	            $stmt_execution = mysqli_stmt_execute($stmt);
            if($stmt_execution === FALSE)
            {
                printf("Error: %s.\n", mysqli_stmt_error($stmt));
                printf("Error: %d.\n", mysqli_stmt_errno($stmt));
                die;
            }
            
            $bind_result = mysqli_stmt_bind_result($stmt,$page_url,$link_anchor_text,$page_description,$keyphrase,$keywords);
            /*RIDDING THIS BASED ON mac_guyver's ADVICE.
            if($bind_result === FALSE)
            {
                printf("Error: %s.\n", mysqli_stmt_error($stmt));
                printf("Error: %d.\n", mysqli_stmt_errno($stmt));
                die;
            }
            */
            
            //$stmt_fetch = mysqli_stmt_fetch($stmt);//I SUSPECT I DO NOT NEED THIS SINCE THERE IS A WHILE LOOP AFTERWARDS.
            
            /*RIDDING THIS BASED ON mac_guyver's ADVICE.
            if($stmt_fetch === FALSE)
            {
                printf("Error: %s.\n", mysqli_stmt_error($stmt));
                printf("Error: %d.\n", mysqli_stmt_errno($stmt));
                die;
            }
            */
            
            while(mysqli_stmt_fetch($stmt))
            {
                echo "$page_url"; echo "<br>";
                echo "$link_anchor_text"; echo "<br>";
                echo "$page_description"; echo "<br>";
                echo "$keyphrase"; echo "<br>";
                echo "$keywords"; echo "<br>";
                echo "|";
                echo "<br>";
            }
            /*RIDDING THIS BASED ON mac_guyver's ADVICE.
            mysqli_stmt_close($stmt);
            mysqli_close($conn);
            */
        }
        else
        {
            die("QUERY failed!");
        }
	 
	<form name = "search" method = "GET">
<label for="keywords">Keywords:*</label>
<input type="text" name="keywords" id="keywords" placeholder="Input Keywords" required>
<br>
<button type="submit">Submit</button><br>
<button type="submit" value="submit">Submit</button><br>
<input type="submit" value="submit"><br>
<button name=submit value=" ">Search</button><br>
<button type="submit" name="submit" value="submit">Search</button>
<br>
<input type="reset">
<br>
</form>
	

 

Since I do not have any params to pass through url, and are not making use of $_GET, are you sure the form method should still be GET ?

Share this post


Link to post
Share on other sites
7 hours ago, 2020 said:

so I'm staying here for the time being

No. You will not.

  • Haha 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • 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.