PHP loop the INSERT MySQL for each result - php

I have already a script which scrapes all the urls of one csv with simple HTML dom.
The output is like this:
CoolerMaster Devastator II Azul
Coolbox DeepTeam - Combo teclado, ratón y alfombrilla
Asus Claymore RED - Teclado gaming
INSERT INTO productos (nombre) VALUES('Asus Claymore RED - Teclado gaming')
Items added to the database!
INSERT INTO productos (nombre) VALUES('Asus Claymore RED - Teclado gaming')
Items added to the database!
INSERT INTO productos (nombre) VALUES('Asus Claymore RED - Teclado gaming')
Items added to the database!
As you can see, the scrape contains 3 different products, but when I try to insert to the MySQL database, it only saves the last product --- but three times.
Here you can see my PHP Code for that:
<?php
require 'libs/simple_html_dom/simple_html_dom.php';
set_time_limit(0);
function scrapUrl($url)
{
$html = new simple_html_dom();
$html->load_file($url);
global $name;
$names = $html->find('h1');
foreach ($names as $name) {
echo $name->innertext;
echo '<br>';
}
$rutaCSV = 'csv/urls1.csv'; // Ruta del csv.
$csv = array_map('str_getcsv', file($rutaCSV));
foreach ($csv as $linea) {
$url = $linea[0];
scrapUrl($url);
}
$servername = "localhost";
$username = "";
$password = "";
$dbname = "";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
foreach ($csv as $linea) {
$url = $linea[0];
$sql = "INSERT INTO productos (nombre) VALUES('$name->plaintext')";
print ("<p> $sql </p>");
if ($conn->query($sql) === TRUE) {
echo "Items added to the database!";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
}
$conn->close();
?>
So, what I need is the MySQL query add:
INSERT INTO productos (nombre) VALUES('CoolerMaster Devastator II Azul')
Items added to the database!
INSERT INTO productos (nombre) VALUES('Coolbox DeepTeam - Combo teclado, ratón y alfombrilla')
Items added to the database!
INSERT INTO productos (nombre) VALUES('Asus Claymore RED - Teclado gaming')
Items added to the database!

You have a bunch of problems in your code.
First, you have function scrapUrl, that takes $url as an argument, but doesn't output anyhting. It's setting global $name variable, but, although it's find several names, it putting only the last one to the $name variable, because it's walking through a series of $names, put it's text into $name, and go for the next one, so, only last item is stored to your $name variable.
I would recommend, that your change your scrapUrl function, so it store names of scrapped products into an array, and return that array.
Second, I'm cannot understand how do you put your data into a csv file, the code, you've privided looks like it shouldn't work properly. Are you sure, that you are writing the right data in a csv file? Maybe here you are just reading data from file - in that case, I'm sorry.
The third: you are reading data from csv, and when moving line by line in the cycle, but the data is going nowhere. To my opinion, you should but $linea[0] into your SQL query, but you are putting $name->plaintext where, when $name is set only once in your scrapUrl, as I've mentioned above.
I would recommend, that you use the right variable in your SQL-query to pass data to it.
Also, it's better to use PDO and prepared statements instead of inserting raw data in your string-literals SQL queries.

Here is your code, just formatted: ( please check it you have a missing } )
function scrapUrl($url)
{
$html = new simple_html_dom();
$html->load_file($url);
global $name; // -- using global is crap - I would avoid that. Pass the object in as an argument of the function eg. scrapUrl($url, $name)
$names = $html->find('h1');
foreach ($names as $name) {
// -- your re-assigning $name overwriting you global on each iteration of this loop
// -- What is the purpose of this? it does nothing but output?
echo $name->innertext;
echo '<br>';
}
// -- missing } where is this function closed at?
$rutaCSV = 'csv/urls1.csv'; // Ruta del csv.
$csv = array_map('str_getcsv', file($rutaCSV));
foreach ($csv as $linea) {
// -- this can be combined with the one with the query
// -- just put the function call in that one and delete this one
$url = $linea[0];
scrapUrl($url); //recursive? depends where you function is closed
// -- whats the purpose of this function, it returns nothing?
}
$servername = "localhost";
$username = "";
$password = "";
$dbname = "";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
foreach ($csv as $linea) {
$url = $linea[0]; // -- whats this url used for?
$sql = "INSERT INTO productos (nombre) VALUES('$name->plaintext')";
// -- query is vulnerable to SQL injection? prepared statement
// -- whats $name->plaintext? where is it assigned at?
print ("<p> $sql </p>");
if ($conn->query($sql) === TRUE) {
echo "Items added to the database!";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
// -- when you loop over the CSV but insert $name->plaintext multiple times
// -- where is that property changed inside this loop, how is it correlated to the csv data
}
$conn->close();
So first off you are missing a closing } Depending where that should be, depends on what else you have wrong.
One of you loops for the CSV can be eliminated ( maybe ), anyway I put bunch of notes in with comments like this // --
Your main issue, or the reason you inserts are the same is these lines
foreach ($csv as $linea) {
$url = $linea[0]; // -- whats this url used for?
$sql = "INSERT INTO productos (nombre) VALUES('$name->plaintext')";
// -- $name->plaintext does not change per iteration of the loop
// -- you are just repeatedly inserting that data
...
See you insert the value of $name->plaintext but this has no correlation to the $csv variable and you are not modifying it. It's no surprise it stays the same.
Ok, now that I picked apart your code ( nothing personal ). Let's see if we can simplify it a bit.
UPDATE This is the best I can do given the above code. I just combined it, fixed some logical errors, trimmed it down and simplified it. It's a common mistake of beginners to over-complicate the task. ( but there is no way for me to test this )
<?php
$servername = "localhost";
$username = "";
$password = "";
$dbname = "";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$rutaCSV = 'csv/urls1.csv'; // Ruta del csv.
$csv = array_map('str_getcsv', file($rutaCSV));
//prepare query outside of the loops
$stmt = $conn->prepare("INSERT INTO productos (nombre)VALUES(?)");
foreach ($csv as $linea) {
//iterate over each csv line
$html = new simple_html_dom();
//load url $linea[0]
$html->load_file($linea[0]);
//find names in the document, and return them
foreach( $html->find('h1') as $name ){
//iterate over each name and bind elements text to the query
$stmt->bind_param('s', $name->plaintext);
if ($stmt->execute()){
echo "Items added to the database!";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
}
}
There I further simplified it as it doesn't really make sense to have the function scrapUrl(). We're not re-using that code, so it adds a function call and makes the code harder to read by having it.
Even if it doesn't work strait away, I encourage you to compare the original code to what I have. And sort of walk through it in your mind, so you can get an feel for how I removed some of those redundancies etc.
For reference
mysqli prepare: http://php.net/manual/en/mysqli.prepare.php
mysqli bind_param: http://php.net/manual/en/mysqli-stmt.bind-param.php
mysqli execute: http://php.net/manual/en/mysqli-stmt.execute.php
Hope that helps, cheers!

Well, after been thinking about this for quite some time, I've managed to make it work.
I leave the code in case someone else can use it.
<?php
require 'libs/simple_html_dom/simple_html_dom.php';
set_time_limit(0);
function scrapUrl($url)
{
$html = new simple_html_dom();
$html->load_file($url);
global $name;
global $price;
global $manufacturer;
$result = array();
foreach($html->find('h1') as $name){
$result[] = $name->plaintext;
echo $name->plaintext;
echo '<br>';
}
foreach($html->find('h2') as $manufacturer){
$result[] = $manufacturer->plaintext;
echo $manufacturer->plaintext;
echo '<br>';
}
foreach($html->find('.our_price_display') as $price){
$result[] = $price->plaintext;
echo $price->plaintext;
echo '<br>';
}
$servername = "localhost";
$username = "";
$password = "";
$dbname = "";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$price_go=str_replace(",",".",str_replace(" €","",$price->plaintext));
$sql = "INSERT INTO productos (nombre, nombreFabricante, precio) VALUES('$name->plaintext', '$manufacturer->plaintext', $price_go)";
print ("<p> $sql </p>");
if ($conn->query($sql) === TRUE) {
echo "Producto añadido al comparador!";
echo '<br>';
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
$conn->close();
//echo $url;
}
$rutaCSV = 'csv/urls1.csv'; // Ruta del csv.
$csv = array_map('str_getcsv', file($rutaCSV));
//print_r($csv); // Verás que es un array donde cada elemento es array con una de las url.
foreach ($csv as $linea) {
$url = $linea[0];
scrapUrl($url);
}
?>
I'm pretty sure i have some trash in my code, but it works.
I hope it help for someone.
Regards and thanks for all the help.

Related

MySQL INSERT in PHP no error feedback

I am trying to input data to MySQL using PHP. Don't know what's wrong. The connection succeeds, no errors but at the end there is not data being written to the database.
$dbhost = "localhost";
$dbname = "listings";
$un = $_POST["un"];
$pass = $_POST["pass"];
$name = $_POST["name"];
$des = $_POST["des"];
$quan = $_POST["quantity"];
$specs = $_POST["specs"];
$price = $_POST["price"];
$url1 = ".";
$url2 = ".";
$url3 = ".";
$url4 = ".";
$connection = mysqli_connect($dbhost,$un,$pass,$dbname);
if (!$connection) {
die("Error".mysqli_error);
} else {
echo "Database connection successfull ".$des;
}
$query = "INSERT INTO items
(name,description,quantity,specs,price,url1,url2,url3,url4) VALUES
'$name','$des','$quan','$specs','$price','$url1','$url2','$url3','$url4')
";
echo "Hellos";
$exeute_query = mysqli_query($query,$connection);
if(!execute_query){
die("error ".mysqli_error());
echo "query error";
} else {
echo "Query successfull";
}
mysqli_close($connection);
Any help?
There are several small mistakes in your code:
$query = "INSERT INTO items (name,description,quantity,specs,price,url1,url2,url3,url4) VALUES ('$name','$des','$quan','$specs','$price','$url1','$url2','$url3','$url4')";
echo "Hellos";
**$exeute_query** = mysqli_query($query,$connection); // $execute_query instead of $exeute_query
if(!**execute_query**){ //$execute_query instead of execute_query
die("error ".mysqli_error());
echo "query error";
}
else{echo "Query successfull";}
mysqli_close($connection);
?>
Your code breaks at the if statement because no fucntion with that name is found (if you do not use the dollarsign to show it is a variable, php will interpret it as a function. Also, when initiating your variable you forgot a 'c' so make sure to check if you have the correct variable name or php won't find your variable. Now your query will work or give an error message in case of wrong data formats or bad connection. Use code listed below to debug your php in the future.
error_reporting(E_ALL);
ini_set('display_errors', 'On');

Inserting form data to a mysql database

I have tried multiple times to get this code to run and insert the data into a my database. No matter what I try I cannot figure out the problem. The php looks like this:
<?php
// Create connection
$conn = mysqli_connect("localhost","nmhsmusi_admin" , "********", "nmhsmusi_musicdb");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
if (isset($_POST['submit']))
{
$titleTag = $_POST['title'];
$composerTag = $_POST['composer'];
$unicodeTag = $_POST['unicode'];
$tempoTag = $_POST['tempo'];
$yearTag = $_POST['year-used'];
$languageTag = $_POST['language'];
$keyTag = $_POST['key-signature'];
$pianoTag = $_POST['piano'];
$temposelTag = $_POST['temposel'];
$partsTag = $_POST['parts'];
$run = mysqli_query($conn,"INSERT INTO musicdb (title, composer, unicode, temptxt, yearused, languages, pianokeys, piano, temposel, parts)
VALUES
(
'$titleTag', '$composerTag', '$unicodeTag', '$tempoTag', '$yearTag', '$languageTag', '$keyTag', '$pianoTag', '$temposelTag', '$partsTag'
)");
if ($run) {
echo "New record created successfully";
} else {
echo "failed";
}
mysqli_close($conn);
}
?>
Any help would be greatly appreciated
Why do you use mysqli? Has it already fallen into disuse?
PDO is now used.
Here's an example:
<?php
if (isset($_POST['submit'])) {
$titleTag = $_POST['title'];
$composerTag = $_POST['composer'];
$unicodeTag = $_POST['unicode'];
$tempoTag = $_POST['tempo'];
$yearTag = $_POST['year-used'];
$languageTag = $_POST['language'];
$keyTag = $_POST['key-signature'];
$pianoTag = $_POST['piano'];
$temposelTag = $_POST['temposel'];
$partsTag = $_POST['parts'];
try {
$pdo = new PDO(DSN,DBUSER,DBUSERPASSWD);
} catch (PDOException $e) {
echo "Failed to connect to Database: " . $e->getMessage() . "\n"; die();
}
$pdo->exec("SET NAMES 'utf8' COLLATE 'utf8_general_ci'");
$sql = "INSERT INTO musicdb (title, composer, unicode, temptxt, yearused, languages, pianokeys, piano, temposel, parts)
VALUES (:titleTag,:composerTag,:unicodeTag,:tempoTag,:yearTag,:languageTag,:keyTag,:pianoTag,:temposelTag,:partsTag)";
$query = $pdo->prepare("$sql");
$query->bindValue(':titleTag',$titleTag);
$query->bindValue(':composerTag',$composerTag);
$query->bindValue(':unicodeTag',$unicodeTag);
$query->bindValue(':tempoTag',$tempoTag);
$query->bindValue(':yearTag',$yearTag);
$query->bindValue(':languageTag',$languageTag);
$query->bindValue(':keyTag',$keyTag);
$query->bindValue(':pianoTag',$pianoTag);
$query->bindValue(':temposelTag',$temposelTag);
$query->bindValue(':partsTag',$partsTag);
$query->execute();
if($query->rowCount() > 0){
echo "New record created successfully!";
} else {
echo "Error!";
}
}
?>
Of course you need to filter everything that comes from the form with regular expressions. Easy thing to do!
Once the regular expressions have analyzed everything you need to convert everything to htmlentities to avoid malicious code:
The regular expression "/([a-zÀ-ÿ0-9\s]+)/i" below allows only letters with or without accents, numbers, and spaces:
<?php
preg_match('/([a-zÀ-ÿ0-9\s]+)/i', $_POST['any_field_form'], $output);
if((isset($output[1]) == true) and ($output[1] != null)) {
//Convert everything to htmlentities to avoid malicious code
$get_the_data = htmlentities($output[1], ENT_QUOTES, 'UTF-8', false);
} else {
$get_the_data = null;
}
?>
With this you avoid problems with forms. Of course for each form field you will have to do a specific regular expression. But that makes your code smarter.
Sorry if there are any errors in the text. I know how to read in English, but I do not know how to write so I used a translator for that.
But that's it, boy!

Export specific strings from xml to mysql table

XML Codes
I have got a item list xml file for a game server, and I need to insert item names, id's and type of the item into a mysql server. I have provided 4 examples of situations, first has isstaffitem="true", second has iscashitem="true" third iscashitem="false" and fourth has nothing regarding item type. Now what I need is to read the id="string", name="string" and type of the item and insert into database. If it's staff item, set type as staff, if cash item set type to cash and set regular if something else.
How can I do that php ? I am trying with $xml = simplexml_load_string($_POST['zitem']); but can't get it work..
Here's some example code. I created a simple HTML-form, with a textarea to input the XML-code. After hitting "Submit", the PHP-script is triggered (server method = post). Connect to your database (example from w3schools). Parse the XML-string as a DomDocument (gives you more options then simple_xml). Insert each item in your xml into MySQL.
<?php
if($_SERVER['REQUEST_METHOD'] == 'POST') {
// Make connection to database first
// example from http://www.w3schools.com/php/php_mysql_insert.asp
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Use DomDocument (more options / flexibility)
$doc = new DOMDocument();
$doc->loadXML($_POST['zitem']);
$items = $dom->getElementsByTagName('ITEM');
foreach ($items as $item) {
// The attributed in the XML item "ITEM", can be retrieved by using $item->getAttribute('nameofattribute')
$id = $item->getAttribute('id');
$name = $item->getAttribute('name');
$mesh_name = $item->getAttribute('mesh_name');
// Some logic, see for yourself.
$cashitem = false;
if ($item->getAttribute('iscashitem') == true) {
$cashitem = true;
}
$staffitem = false;
if ($item->getAttribute('isstaffitem') == true) {
$staffitem = true;
}
// Insert the item from XML into MySQL-table
$sql = "
INSERT INTO Items
(id, name, mesh_name, cashitem, staffitem)
VALUES (
'" . $mysqli->real_escape_string($id) . "',
'" . $mysqli->real_escape_string($name) . "',
'" . $mysqli->real_escape_string($mesh_name) . "',
'somevaluehere',
'somevaluehere'
)";
if ($conn->query($sql) === TRUE) {
echo "New record created successfully";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
}
$conn->close();
}
?>
<form method="post">
<textarea name="zitem"></textarea>
<input type="submit" value="Submit your XML file" />
</form>
Good luck!

fetch_assoc doesn't show first row of results

Not sure what I did wrong. I'm aware that having two fetch_assoc removes the first result but I don't have such a thing.
$sql = "$getdb
WHERE $tablenames.$pricename LIKE 'm9%'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
echo $tableformat;
while($row = $result->fetch_assoc()) {
$name = str_replace('m9', 'M9 Bayonet', $row['Name']);
include 'filename.php';
echo $dbtable;
}
My connect file:
$servername = "";
$username = "";
$dbname = "";
$password = "";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
require_once ('seo.php');
$dollar = '2.';
$euro = '1.9';
$tableformat = "<div class=\"CSSTableGenerator style=\"width:600px;height:150px;\"><table><tr><th>Name</th><th>Price</th><th><a class=\"tooltips\">Community<span>New !</span></a> </th><th>Cash Price</th><th>Trend </th><th>Picture </th></tr></div>";
$getdb = "SELECT utf.id, utf.PriceMin, utf.PriceMax, utf.Name, utf.Trend , community1s.price as com_price, utf.Name, utf.Trend
FROM utf
INNER JOIN (select id, avg(price) price from community1 group by id) as community1s
ON utf.id=community1s.id";
$tablenames = 'utf';
$pricename = 'Name';
$idrange = range(300,380);
What happens is, it fetches the first two column's fine and the rest of the row is not there and pushes the other results down one row, which messes up the data.
Here's an image to demonstrate:
http://imgur.com/CQdnycW
The seo.php file is just a SEO function.
Any ideas on what may be causing this issue?
EDIT:
My Output:
echo $tableformat;
while($row = $result->fetch_assoc()) {
$name = str_replace('m9', 'M9 Bayonet', $row['Name']);
include 'filename.php';
echo $dbtable;
EDIT: Solved it by moving my variables around. Marked as solved.
I found the issue. Some Variables that did the output were in a bad place. Rearranged them and now they are fine.
Your HTML is broken, and strange things happen in broken tables. $tableformat contains HTML that opens a <div> and a <table>, but then closes the <div> with the table still open.
Fix the broken HTML and you'll probably find that all is well

PHP: Duplicate/Blank values when Inserting image names into the DB

I am currently storing in MySQL database image names for easier way to retrieve the actual images. I am having problems with the php code I created that stores the names. Duplicate and blank insertions are being made into the DB without my permission.
Is there a way to avoid this issue of duplicate or blank values being inserted when the page refreshed?
<?
$images = explode(',', $_GET['i']);
$path = Configuration::getUploadUrlPath('medium', 'target');
if (is_array($images)) {
try {
$objDb = new PDO("mysql:host=" . $host . ";dbname=" . $db, $user, $pass);
$objDb->exec('SET CHARACTER SET utf8');
} catch (PDOException $e) {
echo 'There was a problem';
}
$sql = "INSERT INTO `urlImage` (`image_name`) VALUES ";
foreach ($images as $image) {
$value[] = "('" . $image . "')"; // collect imagenames
}
$sql .= implode(',', $value) . ";"; //build query
$objDb->query($sql);
}
?>
First, you should be checking for blank names in your foreach statement, as such:
foreach ($images as $image) {
if($image!='') {
$value[] = "('".$image."')"; // collect imagenames
}
}
Secondly, you should look into header("Location: ..."); to prevent users from refreshing the page.
Thirdly, you could also set a session variable or cookie to prevent a user from uploading the same image twice.
Lastly, if the image names are unique, you can set a UNIQUE index on the image name. Then use INSERT IGNORE and that will remove all of your duplicates.
I reformatted things into what I think should be slightly more readable and more easily separate what's going on in the code. I also updated your queries to show how you can properly "sanitize" your input.
I still think the process by which you're going about sending the data to the server is wrong, but hopefully this code helps you out a little bit. I'd also do this more object orientedly.. but I feel that leaves the scope of your question just a little bit =P. It's kind of like everyone else is saying though, the logic for your code was only off just slightly.
As for the duplication thing, look into checking if the file already exists before adding it to the database.
<?php
$_GET['i'] = 'file1.png, file2.png, file3.png'; // This is just for testing ;].
$images = retrieve_images();
insert_images_into_database($images);
function retrieve_images()
{
//As someone else pointed out, you do not want to use GET for this and instead want to use POST. But my goal here is to clean up your code
//and make it work :].
$images = explode(',', $_GET['i']);
return $images;
}
function insert_images_into_database($images)
{
if(!$images)//There were no images to return
return false;
$pdo = get_database_connection();
foreach($images as $image)
{
$sql = "INSERT INTO `urlImage` (`image_name`) VALUES ( ? )";
$prepared = $pdo->prepare($sql);
$prepared->execute(array($image));
}
}
function get_database_connection()
{
$host = 'localhost';
$db = 'test';
$user = 'root';
$pass = '';
try {
$pdo = new PDO("mysql:host=" . $host . ";dbname=" . $db, $user, $pass);
$pdo->exec('SET CHARACTER SET utf8');
} catch(PDOException $e) {
die('There was a problem');
}
return $pdo;
}
The easiest way to avoid duplicates upon refresh is to re-direct the page after the POST, so just doing header("Location: {$_SERVER['PATH_INFO']}"); should solve that for you.
To avoid empty entries try is_array($images) && count($images)
You probably should change the following line:
if(is_array($images)){
to this:
if(!empty($images) && is_array($images)){
explode() returns an empty array even if no "i" parameter is provided
Try setting a session variable and tell it to exit or redirect when session variable is not set.
For example
if (!isset($_SESSION['session_name']))
{
exit();
}

Categories