I'm having trouble doing updates and inserts on my database using PDO in PHP. The error code notes a success, but the expected changes aren't reflected in the database.
Here's where I set up my connection:
$dsn = "mysql:host=".DB_HOST.";dbname=".DB_NAME;
$db = new PDO($dsn, DB_USER, DB_PASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, FALSE);
I can connect and SELECT on things just fine, but it won't update or insert at all. I've tried just using a hard-coded string, but not even that will work. Here's the code for that:
$ins = "insert into choice_history (id_choice_history,choice_num,choice_taken) values ( 0, 10, 28);";
if($stmt = $this->_db->prepare($ins))
{
$status = $stmt->execute();
return $errorcode = $stmt->errorCode();
}
I have a similar update string but they both have the same results.
Table definition (it has no constraints):
mysql> describe choice_history;
+-------------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| id_choice_history | int(11) | NO | | NULL | |
| choice_taken | int(11) | YES | | NULL | |
| choice_num | int(11) | YES | | NULL | |
+-------------------+---------+------+-----+---------+----------------+
The error code for this is always 00000 (success). I've also tried calling exec() with the same string, but no dice. I can paste that query into mysql on my server and it executes fine, but from PDO nothing happens.
At this point I'm at a loss. PDO reports success but nothing happens in the database. How can I figure out where the problem is?
You have turned auto-commit off, so you need to explicitly commit() all transactions.
Your queries are successful (thus the results you are seeing), they are just never committed.
If you don't want to have to explicitly commit every request, you need to remove this line of code:
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, FALSE);
Related
I'm trying to get the Sphinx search server working with PDO, but it triggers a syntax error when using the MATCH() function in specific scenarios.
Ex.:
In my code I'm splitting the search query by space and then concatenate it using the | (OR) operator. If someone types test > 3, in the match function it would become (test | > | 3). This combination triggers a: Syntax error or access violation: 1064 main_idx: syntax error, unexpected '|' near ' > | 3'. I don't think it's an escape problem because the > character is not on the escape list and even if you try to escape it, it doesn't work. Is this a bug in the version of Sphinx i'm using? Or am I doing something wrong?
I'm using Sphinx version 2.2.11. It's actually a docker instance provided by this image: jamesrwhite/sphinx-alpine:2.2.11
The PHP version is 7.2.
This is my non-working code:
$searchQuery = "SELECT * FROM main_idx WHERE MATCH(:search)";
$dbh = new PDO('mysql:host=127.0.0.1;port=9306', 'root', 'root');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $dbh->prepare($searchQuery);
$stmt->bindValue('search', 'test | > | 3');
$stmt->execute();
Same code works perfectly fine if I'm using the MySQLi extension. It also works fine with PDO and Sphinx version 2.2.6. Something must've changed between 2.2.6 and 2.2.11. Anyone encountered this issue?
This behaviour is caused by this bug http://sphinxsearch.com/bugs/view.php?id=2305 and this fix https://github.com/sphinxsearch/sphinx/commit/d9923f76c7724fa8d05a3d328e26a664799841b7. In the previous revision ' > | ' was supported.
We at Manticore Search (fork of Sphinx) will check if the fix was correct and will make a better fix if that's not. Thanks for pointing this out.
Meanwhile you can use 2.2.8 from http://sphinxsearch.com/downloads/archive/ or build manually from the latest revision which supports the syntax (https://github.com/sphinxsearch/sphinx/commit/f33fa667fbfd2031ff072354ade4b050649fbd4e)
[UPDATE]
The fix is proper. It was wrong to not show the error about that in the previous versions as long as you DON'T have the spec. character (>) in your charset_table. To workaround this you can add > to your charset_table and then escape it in the search query, e.g.:
mysql> select * from idx_min where match('test | \\> | a');
+------+---------+----------+-------+------+
| id | doc | group_id | color | size |
+------+---------+----------+-------+------+
| 7 | dog > < | 5 | red | 3 |
+------+---------+----------+-------+------+
1 row in set (0.00 sec)
mysql> select * from idx_min where match('test | \\< | a');
+------+---------+----------+-------+------+
| id | doc | group_id | color | size |
+------+---------+----------+-------+------+
| 7 | dog > < | 5 | red | 3 |
+------+---------+----------+-------+------+
1 row in set (0.00 sec)
or
$stmt->bindValue('search', 'test | \\< | a');
in PDO.
There's still a little bug found though which is that if non-spec character is not in charset_table it doesn't generate an error. E.g.
mysql> select * from idx_min where match('test | j | a');
Empty set (0.00 sec)
works fine even though j is not in charset_table. I've filed a bug in our bug tracker https://github.com/manticoresoftware/manticoresearch/issues/156
Thanks again for helping to point this out.
say for exmple you want to do an exact match I like doing my exact matching like this...
...WHERE MATCH(column) AGAINST('happy I am') AND column LIKE '%happy I am%';
that will guarantee I match exactly what I want to match where as if I didn't include the AND LIKE... it would match happy OR I OR am
So I have this table:
mysql> DESCRIBE table;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(15) unsigned | NO | PRI | NULL | auto_increment |
| unid | char(9) | NO | UNI | NULL | |
| rs | varchar(255) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
Which contains millions of rows:
mysql> SELECT COUNT(1) FROM table;
+----------+
| COUNT(1) |
+----------+
| 9435361 |
+----------+
1 row in set (0.00 sec)
I'm willing to export all rows in a .csv file (I'm using Symfony2.6). This file is meant to be stored on the server (not downloaded) and later on, read by PHP.
1st attempt
I tried to make a huge request to select all at once (as per this blog post) but this has, despite the use of ->iterate(), led to Allowed memory size of 1073741824 bytes exhausted after having run for ~9s.
ini_set('memory_limit', '1024M');
ini_set('max_execution_time', -1);
$results = $em
->getRepository('MyBundle:Entity')
->createQueryBuilder('e')
->getQuery()
->iterate();
$handle = fopen('/path/to/csv/file/', 'w');
while (false !== ($row = $results->next())) {
fputcsv($handle, $row[0]->toArray());
$em->detach($row[0]);
}
fclose($handle);
2nd attempt
I retrieved the total of rows and then, did a loop to make the same number of queries to retrieve rows one by one. But after having written ~260K rows into the .csv file, PHP runs out of memory and throws the same error as above : Allowed memory size of 1073741824 bytes exhausted.
ini_set('memory_limit', '1024M');
ini_set('max_execution_time', -1);
$total = (int) $em
->getRepository('MyBundle:Entity')
->countAll();
$csv = '/path/to/csv/file';
$handle = fopen($csv, 'w');
for($i = 1; $i < $total; $i++)
{
$entity = $em->getRepository('MyBundle:Entity')->findOneById($i);
fputcsv($handle, $entity->toArray());
$em->detach($entity);
}
fclose($handle);
3rd attempt
I have thought of the use of the exec() function to run the MySQL command line that would export the table. However, my manager seems not to like this option.
So am I making a fool of myself thinking that dumping ~9.5M of rows using PHP into a .csv file is even possible? Are there any other way I'm not yet aware of?
Thanks for your help on this one.
Rather than attempting to build the object-tree, you could directly try to select the result into a file: http://dev.mysql.com/doc/refman/5.7/en/select.html
Something like
SELECT * INTO OUTFILE "c:/temp/mycsv.csv"
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY "\n"
FROM theTable;
This should leave the job up to mysql and bypass any php memory limitations.
As venca noted: In this case the user under which you are running the mysql service needs write permissions to the directory in question.
Ok, I have such script
#!/bin/bash
keyOrPass=$1
intercom=$2
flat=$3
number=$4
mysql -ulogin -ppass db_name -e "select cli.codeGuestEmail, cli.codePrivateEmail, cliKey.rf_id, cliKey.emailNotification from mbus_clients as cli join mbusClientKeys as cliKey on cliKey.id_client=cli.id WHERE cli.flat=${flat} and cli.domophone=${intercom};";
php -q sendNotifications.php
It works fine, but I should pass some result fields from select into php arguments. Any ideas how to do it?
OUTPUT:
+----------------+------------------+------------+-------------------+
| codeGuestEmail | codePrivateEmail | rf_id | emailNotification |
+----------------+------------------+------------+-------------------+
| 1 | 0 | 2774490192 | 0 |
| 1 | 0 | 2774490193 | 0 |
| 1 | 0 | 2774490194 | 0 |
| 1 | 0 | 2774490195 | 1 |
+----------------+------------------+------------+-------------------+
mysql is capable of generating output formatted differently. With the -B or --batch option, mysql produces the output with TAB as the column separator. The special characters in the fields are escaped (e.g. TAB is output as "\t") so you can use cut to extract fields.
Many times in cases like this it's helpful to use the -N or --skip-column-names option as well, in order to remove column names from the output.
I'm trying to figure out how to use a regex search on a MySQL column to update some data.
The problem is I'm trying to rename part of a URL (i.e a directory).
The table looks something like this (although it's just an example, the actual data is arbitrary):
myTable:
| user_name | URL |
| ------------- |:---------------------------------------------------------:|
| John | http://example.com/path/to/Directory/something/something |
| Jane | http://example.com/path/to/Directory/something/else |
| Jeff | http://example.com/path/to/Directory/something/imgae.jpg |
I need to replace all the URLs that have "path/to/Directory/" to "path/to/anotherDirectory/" while keeping the rest of URL intact.
So the result after the update should look like this:
| user_name | URL |
| ------------- |:----------------------------------------------------------------:|
| John | http://example.com/path/to/anotherDirectory/something/something |
| Jane | http://example.com/path/to/anotherDirectory/something/else |
| Jeff | http://example.com/path/to/anotherDirectory/something/imgae.jpg |
At the moment, the only way I could figure out how to do it is using a combination of regex quires to check for the directory, and then loop over it and change the URL, like this:
$changeArr = $db->query("SELECT URL FROM myTable WHERE URL REGEXP 'path/to/Directory/.+'");
$URLtoChange = "path/to/Directory/";
$replace = "path/to/anotherDirectory/"
foreach ($changeArr as $URL) {
$replace = str_replace($URLtoChange, $replace, $URL);
$db->query("UPDATE myTable SET URL = :newURL WHERE URL = :URL", array("URL"=>$URL,"newURL"=>$replace));
}
This seems to work pretty well, however with such with a big table it can be pretty heavy on performance.
I was wondering if there's a more efficient way to do this? Perhaps with some sort of regex replace in a mySQL query.
Just use the REPLACE() function:
UPDATE myTable
SET URL = REPLACE(url, 'path/to/Directory/', 'path/to/anotherDirectory/')
WHERE URL LIKE '%path/to/Directory/%'
Answers provided have all been great, I mentioned in the comments of Alnitak's answer that I would need to go take a look at my CSV Generation script because for whatever reason it wasn't outputting UTF-8.
As was correctly pointed out, it WAS outputting UTF-8 - the problem existed with Ye Olde Microsoft Excel which wasn't picking up the encoding the way I would have liked.
My existing CSV generation looked something like:
// Create file and exit;
$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");
echo $csv_output;
It now looks like:
// Create file and exit;
$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: text/csv; charset=ISO-8859-1");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header("Content-disposition: filename=".$filename.".csv");
echo iconv('UTF-8', 'ISO-8859-1', $csv_output);
-------------------------------------------------------
ORIGINAL QUESTION
Hi,
I've got a form which collects data, form works ok but I've just noticed that if someone types or uses a '£' symbol, the MySQL DB ends up with '£'.
Not really sure where or how to stop this from happening, code and DB information to follow:
MySQL details
mysql> SHOW COLUMNS FROM fraud_report;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | mediumint(9) | | PRI | NULL | auto_increment |
| crm_number | varchar(32) | YES | | NULL | |
| datacash_ref | varchar(32) | YES | | NULL | |
| amount | varchar(32) | YES | | NULL | |
| sales_date | varchar(32) | YES | | NULL | |
| domain | varchar(32) | YES | | NULL | |
| date_added | datetime | YES | | NULL | |
| agent_added | varchar(32) | YES | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
8 rows in set (0.03 sec)
PHP Function
function processFraudForm($crm_number, $datacash_ref, $amount, $sales_date, $domain, $agent_added) {
// Insert Data to DB
$sql = "INSERT INTO fraud_report (id, crm_number, datacash_ref, amount, sales_date, domain, date_added, agent_added) VALUES (NULL, '$crm_number', '$datacash_ref', '$amount', '$sales_date', '$domain', NOW(), '$agent_added')";
$result = mysql_query($sql) or die (mysql_error());
if ($result) {
$outcome = "<div id=\"success\">Emails sent and database updated.</div>";
} else {
$outcome = "<div id=\"error\">Something went wrong!</div>";
}
return $outcome;
}
Example DB Entry
+----+------------+--------------+---------+------------+--------------------+---------------------+------------------+
| id | crm_number | datacash_ref | amount | sales_date | domain | date_added | agent_added |
+----+------------+--------------+---------+------------+--------------------+---------------------+------------------+
| 13 | 100xxxxxxx | 10000000 | £10.93 | 18/12/08 | blargh.com | 2008-12-22 10:53:53 | agent.name |
What you're seeing is UTF-8 encoding - it's a way of storing Unicode characters in a relatively compact format.
The pound symbol has value 0x00a3 in Unicode, but when it's written in UTF-8 that becomes 0xc2 0xa3 and that's what's stored in the database. It seems that your database table is already set to use UTF-8 encoding. This is a good thing!
If you pull the value back out from the database and display it on a UTF-8 compatible terminal (or on a web page that's declared as being UTF-8 encoded) it will look like a normal pound sign again.
£ is 0xC2 0xA3 which is the UTF-8 encoding for £ symbol - so you're storing it as UTF-8, but presumably viewing it as Latin-1 or something other than UTF-8
It's useful to know how to spot and decode UTF-8 by hand - check the wikipedia page for info on how the encoding works:
0xC2A3 = 110 00010 10 100011
The bold parts are the actual
"payload", which gives 10100011,
which is 0xA3, the pound symbol.
In PHP, another small scale solution is to do a string conversion on the returned utf8 string:
print iconv('UTF-8', 'ASCII//TRANSLIT', "Mystring â"); //"Mystring "
Or in other platforms fire a system call to the inconv command (linux / osx)
http://php.net/manual/en/function.iconv.php#83238
You need to serve your HTML in utf-8 encoding (actually everyone needs to do this I think!)
Header like:
Content-Type: text/html; charset=UTF-8
Or the equivalent. Double check the details though. Should always be declaring the charset as a browser can default to anything it likes.
To remove a  use:
$column = str_replace("\xc2\xa0", '', $column);
Credits among others: How to remove all occurrences of c2a0 in a string with PHP?
Thanks a lot. I had been suspecting mysql for being currupting the pound symbol. Now all i need to do is wherever the csv record is generated, just use wrap them incov funciton. Though this is a good job, I am happy, at least someone showed exactly what to do. I sincerly appreciate dislaying the previous and the new 'header' values. It was a great help to me.
-mark
If you save line "The £50,000 Development Challenge" in two different data type column i.e. "varchar" & "text" field.
Before i save i have replaced the symbol with html equi value using following function.
str_replace("£", "£", $title);
You will find that value stored in text fields is £ where as in varchar its "£".