Mysql string input with formatting - php

I am a beginner at MySQL and I am having a little trouble with the correct formatting for a cell in my table.
I have the data type set to TEXT so there is plenty of space for a few small paragraphs within the cell however my problem is, how do I format the paragraph with apostrophes, quotes, colons, and other punctuation that I am inserting into that cell via command line (MAC)?
This is what the column values are:
joke TEXT NOT NULL,
I want to insert this example joke into the table:
Husband says: "When I'm gone you'll never find another man like me".
Wife replied: "What makes you think I'd want another man like you!"
How do I write it into command line so it will display the exact formatting or at least something close. My command line entry looks like this:
INSERT INTO jokes
(date_submitted, source, joke_style, joke)
VALUES
(NOW(), 'www.example.com','Blonde', 'Joke would go here with (: ' ,) and so on.');
Do I escape the apostrophes with \'? What do I do with the rest of the punctuation, and how do I store line breaks?

Use mysql_real_escape_string() or switch to PDO and use PDO::prepare() with placeholders.
Example:
$sth = $pdo->prepare('INSERT INTO jokes ... VALUES (NOW, :joke, ...)');
$sth->execute(array(':joke' => $joke));
If you need to write commands manually, you should escape ' as \', and the newline character is \n. For more details about how strings are escaped in MySQL, see the manual section about string literals.

heres an excerpt from the manual
The following SELECT statements demonstrate how quoting and escaping work:
mysql> SELECT 'hello', '"hello"', '""hello""', 'hel''lo', '\'hello';
+-------+---------+-----------+--------+--------+
| hello | "hello" | ""hello"" | hel'lo | 'hello |
+-------+---------+-----------+--------+--------+
mysql> SELECT "hello", "'hello'", "''hello''", "hel""lo", "\"hello";
+-------+---------+-----------+--------+--------+
| hello | 'hello' | ''hello'' | hel"lo | "hello |
+-------+---------+-----------+--------+--------+
mysql> SELECT 'This\nIs\nFour\nLines';
+--------------------+
| This
Is
Four
Lines |
+--------------------+
mysql> SELECT 'disappearing\ backslash';
+------------------------+
| disappearing backslash |
+------------------------+

Related

Different Variants of UTF-8 Comma? [,] [,] - CURL Response for MySQL Data

Prepping a Curl Response for particular data to be inserted into a MySQL Table.
Noticed some special characters in the saved data for certain URL's.
$curldata = curl_exec($curl);
$encoding = mb_detect_encoding($curldata);
brought back ASCII encoding.
Okay, don't want that.
The tables in my database are an InnoDB type with a utf8mb4_unicode_ci collation.
Added this to my curl options:
curl_setopt($curl, CURLOPT_ENCODING, 1);
And an iconv function based on the above mb_detect_encoding / $encoding variable upon save.
$curldata = iconv($encoding, "UTF-8", $curldata);
// save to file to test output
file_put_contents('test.html', $curldata);
Not sure if this is the best way to go about this, but my test.html output no longer has any encoding for special characters, so... (perhaps) mission accomplished.
As I parse through the data, I then notice this character.
,
Not an ordinary comma... [Comparison: ,/,]
But acts like one. Try doing a ctrl+f and try to find a comma. It treats them as the same, and both as a UTF-8 character - var_dump(mb_detect_encoding(','));
I look at my table row, and see it as a row inserted as such
8,8
If I try to search for a , it does indeed bring back the instances where ,is present.
Vice versa, if I search for , it brings back all instances where that and a comma occurs.
Basically for all intents and purposes it is a comma, yet obviously isn't.
This is of course workable, but rather annoying and feels riddled with inconsistency.
Can anyone explain why the two commas are the same, yet obviously different?
Is there a solution for me to prevent these odd characters from entering my CURL response, or further in within my DOM response and PDO Insert.
edit:
If relevant,
// dom
$dom = new DOMDocument('1.0', 'utf-8');
libxml_use_internal_errors(true);
$dom->preserveWhiteSpace = FALSE;
$dom->loadHTML(mb_convert_encoding($curldata, 'HTML-ENTITIES', 'UTF-8'));
// pdo
$pdoquery = "INSERT INTO `table` (`Attr`) VALUES (?)";
$value = "8,8";
$stmt = $pdo->prepare("INSERT INTO `table` (`Attr`) VALUES (?)");
$stmt->execute([$value]);
edit 2:
Well, it appears to be a FULLWIDTH COMMA..
var_dump(utf8_to_unicode(','));
string '%uff0c' (length=6)
var_dump(utf8_to_unicode(','));
string '%2c' (length=3)
Starting to make more sense... now to figure out how to prevent such characters from entering the curl response/DOM/database...
You might want the function mb_convert_kana which can convert characters of different widths into a uniform width.
$s = 'This is a string with ,, (commas having different widths)';
echo 'original : ', $s, PHP_EOL;
echo 'converted: ', mb_convert_kana($s, 'a');
result:
original : This is a string with ,, (commas having different widths)
converted: This is a string with ,, (commas having different widths)
PHP documentation: mb_convert_kana
To get an idea what the meaning is, see also http://unicode.org/reports/tr11-2/
By convention, 1/2 Em wide characters of East Asian legacy encodings are called "half-width" (or hankaku characters in Japanese), the others are called correspondingly "full-width" (or zenkaku) characters.
With a suitable COLLATION, the two commas are treated as equal:
mysql> SELECT ',' = ',' COLLATE utf8mb4_general_ci;
+----------------------------------------+
| ',' = ',' COLLATE utf8mb4_general_ci |
+----------------------------------------+
| 0 |
+----------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT ',' = ',' COLLATE utf8mb4_unicode_ci;
+----------------------------------------+
| ',' = ',' COLLATE utf8mb4_unicode_ci |
+----------------------------------------+
| 1 |
+----------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT ',' = ',' COLLATE utf8mb4_unicode_520_ci;
+--------------------------------------------+
| ',' = ',' COLLATE utf8mb4_unicode_520_ci |
+--------------------------------------------+
| 1 |
+--------------------------------------------+
1 row in set (0.00 sec)
It would be better to talk in terms of HEX, not unicode:
mysql> SELECT HEX(','), HEX(',');
+------------+----------+
| HEX(',') | HEX(',') |
+------------+----------+
| EFBC8C | 2C |
+------------+----------+
1 row in set (0.00 sec)

Sphinx: PDO exception with certain characters

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

Use like with PDO on JSON-String

Actualy I know how to use LIKE statement with PDO
Now I have a DB-Table called e.g. foobar
foobar contains a JSON-String like:
{"firstname":"foo","email":"aaa#aaa.aa","lastname":"bar"}
Now before I call my INSERT on the table I want to check if the Email is already in use.
$pdo->query("SELECT * FROM myTable WHERE foobar LIKE ?", array('%' . $email . '%'));
as you can see, I pass the email into the pdo query.
Notice ->query is my custom function that handles some stuff. In this case its not important to know what happens.
The problem I have is:
If the entry like above exists then its not possible anymore to add an email thats like:
aa#aaa.aa
^^....only two A's
So I thought I can simply change
array('%' . $email . '%')
to
array('%"' . $email . '"%')
but this doesnt work. Is there a way I can check the whole string part ?
{"firstname":"foo","email":"aaa#aaa.aa","lastname":"bar"}
If you can't break the JSON fields into their own columns, then I would suggest a JSON column type. It's native to MySQL, super fast for JSON of this size, and no more difficult to use than something like jq on the command line.
If that's not an option, I would use a REGEXP:
mysql> select * from foobar;
+-----------------------------------------------------------+
| json |
+-----------------------------------------------------------+
| {"firstname":"foo","email":"aaa#aaa.aa","lastname":"bar"} |
| {"firstname":"FOO","email":"aa#aaa.aa","lastname":"BAR"} |
+-----------------------------------------------------------+
mysql> select * from foobar where json regexp '"email":"aa#aaa.aa"';
+----------------------------------------------------------+
| json |
+----------------------------------------------------------+
| {"firstname":"FOO","email":"aa#aaa.aa","lastname":"BAR"} |
+----------------------------------------------------------+
1 row in set (0.00 sec)
This is serviceable, but hardly bullet-proof and, to borrow an excellent turn of phrase, will murder performance on anything but trivial row sets.

How to escape a # within a SQL CONCAT for anchor in URL

I'm setting up a database query to access and link to comments, but I am having trouble escaping the # symbol within the CONCAT. Here is my current query:
SELECT c.subject, CONCAT('node/', c.nid, '/comment-', c.cid) FROM {comments} c WHERE c.subject LIKE LOWER(:like_word)
Which creates urls like this: node/1234/comment-1234
I need to include the # to create a url like so: node/1234/#comment-1234 but that doesn't work due to the # sign.
SELECT c.subject, CONCAT('node/', c.nid, '/#comment-', c.cid) FROM {comments} c WHERE c.subject LIKE LOWER(:like_word)
Can you provide some more details? You say it "doesn't work due to the # sign". How does it not work? Do you get an error? Is the resulting string not what you expected?
I tried a test here on MySQL 5.5 and got what seems like a normal response:
mysql> select concat('foo/', 'bar', '/#comment');
+------------------------------------+
| concat('foo/', 'bar', '/#comment') |
+------------------------------------+
| foo/bar/#comment |
+------------------------------------+
1 row in set (0.00 sec)

how to trace duplicate data

I would like to ask something here.
now I make form that insert data into table.
this table kemaskini that already have
+------+----------+----------+
| no | Item | kuantiti |
+------+----------+----------+
| 1 | Speaker | 10 |
+------+----------+----------+
| 2 | Laptop | 10 |
+------+----------+----------+
| 3 | Mouse | 10 |
+------+----------+----------+
when I type "Speaker" in form then I submit it.
it trace and say try again. it because already have.
coding that I write here. it only trace row 1 of table kemaskini.
when I type "Laptop" in form then I submit it.
it insert normally.
i more thing how I can trace "Speaker" and "speaker" are same.
if (isset($_POST['submit']))
{
$result = mysql_query("SELECT Item FROM kemaskini");
$test = mysql_fetch_array($result);
$trace=$test['Item'];
if($_POST['Item']==$trace)
{
echo "Try Again";
}
else
{
$item=$_POST['Item'] ;
$kuantiti= $_POST['kuantiti'] ;
mysql_query("INSERT INTO `kemaskini`(Item,kuantiti)
VALUES ('$item','$kuantiti')");
header("Location: kemaskini.php");
}
}
The reason for that is because you are not looping the result from mysql_fetch_array() that is why you are only checking for the first value of the result. If you don't want to Iterate, you can change the query into:
$itemToSearch = "Speaker";
$result = mysql_query("SELECT COUNT(*) result
FROM kemaskini
WHERE Item = '$itemToSearch'")
which will give you the total number of items found,
$test = mysql_fetch_array($result);
$trace = $test['result'];
if($trace > 0)
{
echo "Try Again";
}
else
{
// insert value
}
As a sidenote, the query is vulnerable with SQL Injection if the value(s) of the variables came from the outside. Please take a look at the article below to learn how to prevent from it. By using PreparedStatements you can get rid of using single quotes around values.
How to prevent SQL injection in PHP?
Regarding, how can you trace "Speaker" and "speaker" are the same, you can use the upper() or lower() function that most database engines support. I don't work with mysql so I am going on an assumption here. Your check would be something like this:
select count(*) records
from kemaskini
where lower(item) = 'speaker'
Having said that, I have to warn you that using functions in the where clause like this make your queries run slower.
If JW's comment about PreparedStatements includes using query parameters (I don't work with php either), it's very good advice. Not only do they increase the security of your applications, but they escape special characters such as apostrophes. Since you are doing a character search, you would not want your query to crash if the user submitted something like "Dave's keyboard" to your application.

Categories