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/%'
Related
I have a CakePHP application that uses Fields to store values like 0, 1, 2.
Table:
+----+--------+----------------+
| id | status | title |
+----+--------+----------------+
| 1 | 2 | something new |
| 2 | 1 | nsfw |
| 3 | 1 | a potato |
| 5 | 0 | the real thing |
+----+--------+----------------+
Entity/ Array:
$data = [
0 => 'not published',
1 => 'published',
2 => 'draft',
9 => 'option',
];
// Some public methods to get the data..
Template Form dropdown:
+----+---------------+
| id | value |
+----+---------------+
| 0 | not published |
| 1 | published |
| 2 | draft |
| 9 | option |
+----+---------------+
What I use in template:
echo $this->Form->input('status', ['options' => $article->getArticleStatusList()]);
Example:
articles table with a status field. The default values are: 0 not published, 1 published, etc. Defining those in Entity/Article. There is an array with the default values, so in the template file I call an Entity method that uses the array for the options Form input.
Time ago I was using a configuration array for this.
Is this a good way to accomplish the task? It should be stored in a ini file? Or in a Table/Model?
All works but I want to follow the MVC pattern. Thanks.
Put them in src\Model\ArticleStatus.php. At least for me a status is a list of one or more things that don't change very often. No need to put them in a DB table. These lists are data and clearly belong into the model layer of the MVC pattern.
IMHO it is good practice to use constants for them because you'll do a lot checks in the code against these values. String values are prone to typos and hard to distinguish from other domains. For example if you have two tables using a status of the same name but with a different meaning the code can become tricky to understand and also a search and replace won't work very well because you'll change both types for both domains.
For example we have a countries table with a lot additional info per country but use a list of constants of our ~18 most used countries we have to do conditional checks on because of our business. So we have src\Model\Table\CountriesTable.php but as well src\Model\Country.php. The reason for this is it becomes much much more readable and easier to understand what goes in the the code if you can write Country::GERMANY instead of just using an id like 5. I personally consider it as very bad practice to use hard coded id's everywhere in the code.
if ($country === 41 && $status === 3)
vs
if ($country === Country::GERMANY && $status === ArticleStatus::PUBLISHED)
I think we can agree on that readable and easy to understand code is much better than typing a few characters less. Honestly, people whining about a few characters should learn to type faster. I consider it just as a bad excuse. ;) Also using an IDE will autocomplete the class constants any way for you. It won't do that for an integer.
Here is an example that would even allow you to generate your list with translated labels:
<?php
namespace App\Model;
class ArticleStatus {
const PUBLISHED = 'published';
const DRAFT = 'draft';
// Add more as you like
public static function getStatuses() {
return [
static::PUBLISHED ,
static::DRAFT
];
}
public static function getKeyValueList() {
return [
static::PUBLISHED => __d('app', 'Published'),
static::DRAFT=> __d('app', 'Draft')
];
}
}
Use it in your controller and set it to your view or directly use it in the view.
I have the above table: tblCompInfo, the product_id value is not 100% accurate and I need to fix it. I have total of 543847 total row with 25 different company and 12 different products.
now, The URL is 100% accurate and as you can see from the image I have highlighted with RED which means they are wrong and GREEN which is what it should be updated to.
TASK:
I need to update Product_id by parsing through URL and getting the INTEGER and checking it with product table, if its a product, assign the value else assign 0.
SOLUTION:
I got two solution in my head:
1. EXPORT the entire DATA to EXCEL CVS, change it and UPLOAD it to DATABASE. which means my entire week will be working with EXCEL only.
2. Since I have laravel framework: I can make a function in PHP and get the DATA company wise and UPDATE the table in a foreach loop with condition.
PROBLEM:
So, to make my life easy, I made the PHP function with a simple solution and it works BUT I get MEMORY ALLOCATION PROBLEM.
$companyID = ??;
$tblCompInfos = tblCompInfo::where('company_id', '=', $companyID)->get();
foreach($tblCompInfos as $tblCompInfo)
{
$actual_link = $tblCompInfo->url;
$pathlink = parse_url($actual_link, PHP_URL_PATH);
$product_id_from_url = preg_replace("/[^0-9]/", "" , $pathlink);
$FindIfItsInProductTable = Product::find($product_id_from_url);
$real_product_id = $FindIfItsInProductTable == null ? 0 : $product_id_from_url;
DB::table('tblCompInfo')->where('company_id', '=', $companyID)->where('url', '=', $tblCompInfo->url)->update(array(
'product_id' => $real_product_id,
));
echo $actual_link."-".$real_product_id."=".$tblCompInfo->product_id."<br>";
}
if it was a local server, I would have update my PHP.ini with more memory and do the job.
However, I have a LIVE server and it has to be done in the live server and I have no control or power over PHP.ini.
What to do? How can I do it easily that I will not get a memory issue?
Please help if anyone?
Try this :
UPDATE [table_name] SET product_id = CONVERT(SUBSTR(url, LOCATE('products/', url)+9, LOCATE('/compare',url)-LOCATE('products/', url)+9),UNSIGNED INTEGER)
But this will only works if every url field has suffix as /compare
if you use MariaDB you can use REGEXP_REPLACE to do the changes like
UPDATE your_table
SET url = REGEXP_REPLACE(url,'[0-9]+',Product_id)
WHERE Product_id > 0;
sample
MariaDB [your_schema]> SELECT REGEXP_REPLACE('http://example.com/products/12/compare','[0-9]+','99');
+--------------------------------------------------------------------+
| REGEXP_REPLACE('http://example.com/products/12/compare','[0-9]+','99') |
+--------------------------------------------------------------------+
| http://example.com/products/99/compare |
+--------------------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [your_schema]>
I have a pretty odd idea but it can work.
Look at that query :
SELECT
'http://example.com/products/12/compare' as url,
'http://example.com/products/' as check1,
'http://example.com/termsets/' as check2,
'http://example.com/products/12/compare' REGEXP 'http://example.com/products/' as regexp_check1, -- check 1
SUBSTRING('http://example.com/products/12/compare', LOCATE('http://example.com/products/','http://example.com/products/12/compare')+LENGTH('http://example.com/products/'),1 ) as test1,
SUBSTRING('http://example.com/products/12/compare', LOCATE('http://example.com/products/','http://example.com/products/12/compare')+LENGTH('http://example.com/products/'),1 ) REGEXP "^[0-9]+$" as test1_only_num,
SUBSTRING('http://example.com/products/12/compare', LOCATE('http://example.com/products/','http://example.com/products/12/compare')+LENGTH('http://example.com/products/'),2 ) as test11,
SUBSTRING('http://example.com/products/12/compare', LOCATE('http://example.com/products/','http://example.com/products/12/compare')+LENGTH('http://example.com/products/'),1 ) REGEXP "^[0-9]+$" as test11_only_num,
SUBSTRING('http://example.com/products/12/compare', LOCATE('http://example.com/products/','http://example.com/products/12/compare')+LENGTH('http://example.com/products/'),3 ) as test111,
SUBSTRING('http://example.com/products/12/compare', LOCATE('http://example.com/products/','http://example.com/products/12/compare')+LENGTH('http://example.com/products/'),1 ) REGEXP "^[0-9]+$" as test111_only_num;
Result :
+----------------------------------------+------------------------------+------------------------------+---------------+-------+----------------+--------+-----------------+---------+------------------+
| url | check1 | check2 | regexp_check1 | test1 | test1_only_num | test11 | test11_only_num | test111 | test111_only_num |
+----------------------------------------+------------------------------+------------------------------+---------------+-------+----------------+--------+-----------------+---------+------------------+
| http://example.com/products/12/compare | http://example.com/products/ | http://example.com/termsets/ | 1 | 1 | 1 | 12 | 1 | 12/ | 0 |
+----------------------------------------+------------------------------+------------------------------+---------------+-------+----------------+--------+-----------------+---------+------------------+
Url, check1 and check2 are just to display the variables I'm using. It's a main ID, the query is not usable that way of course.
Logic with check1
You check with a REGEX if check1 is present in your URL. If yes, regexp_check1 is 1, else it's 0.
ONLY if regexp_check1 is 1, then you SUBSTRING your URL to take the part that is located AFTER the check1 sentence. You take the first character AFTER (test1), then the two characters AFTER (test11), the three characters AFTER (test111) etc.. until the max length your ID_PRODUCT can be (6 or 7 for example).
You REGEX the SUBSTR you isolated to check if they are numeric only (test1 is numeric, test11 is numeric only, test111 is not numeric only.
Then you know that the content of test11 is your ID
Then you do the same thing with check2 if regexp_check1 was 0, and with an eventual check3 (which would contain http://www.comadso.dk/products/ for example), and for every beginning you can have.
Maybe my idea is a shitty one, but hey if it's seem dumb but works, it's not dumb !
So I am creating a website for me and my friends so we can work on projects with each other (Like Google documents), and I am trying to create a thing so we can choose what project we want to work on. Currently I am having trouble getting the names of the projects from the MySQL table.
Here is what I have tried to get the names of the projects
$projects = mysqli_query($link, "SELECT * FROM table WHERE name='". $username ."'");
$projects2 = mysqli_fetch_assoc($projects);
$projects3 = $projects2["projectname"];
And here is an example of the MySQL table
+---------+------------------+------------------+------------------+------------
-+
| name | htmltext | csstext | jstext | projectname
|
+---------+------------------+------------------+------------------+------------
-+
| cow9000 | testing is cool! | testing is cool! | testing is cool! | test
|
| cow9000 | testing is cool! | testing is cool! | testing is cool! | test2
|
+---------+------------------+------------------+------------------+------------
As you can see there are 2 documents that the owner owns, but when I try printing out $project3, it only gives me "test". How would I change my code to get all projectname values?
Sorry if this is confusing, it is hard for me to put it into words. Also, please do point out errors in my code as I only have a couple days of experience in PHP and MySQL (But I am finding that PHP and MySQL is very, very easy for me.)
You already have all of those values. You just access them like you did projectname, by using the name of that column as the key in the $projects2 array:
$projects2 = mysqli_fetch_assoc($projects);
echo $projects2["name"]; // cow9000
echo $projects2["htmltext"]; // testing is cool!
echo $projects2["csstext"]; // testing is cool!
echo $projects2["jstext"]; // testing is cool!
If you want the second row you need to use a loop:
// Prints each row in the order they were retrieved
while($projects2 = mysqli_fetch_assoc($projects)) {
echo $projects2["projectname"]; // test and then test2
}
You have to iterate through the returned data, for example like this:
while ($projects2 = mysqli_fetch_assoc($projects)) {
echo $projects2["projectname"];
}
First it will return test, second test2
I am working in PHP using strstr() to remove values which are extracted from a MYSQL db to be outputted to an excel file-
CODE:
If (!strstr($value, '<script>')){
$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($col, $row, $value);
$row++;
}
This code excludes the columns that contain a <script> tag. However it shifts the contents of the cells up like so:
=====================================
|Question | Answer |
=====+========+===============+=====|
| Male/female | |
|----+--------+---------------+-----|
| | F |
|----+--------+---------------+-----|
Instead I would like it to skip the rows like so:
=====================================
|Question | Answer |
=====+========+===============+=====|
| | |
|----+--------+---------------+-----|
| Male/female | F |
|----+--------+---------------+-----|
Your code is written so that the row is only incremented if your script tag is not found. However, it sounds like you want to unconditionally increment; if that's the case, then move $row++ to outside the if statement, like so:
if (!strstr($value, '<script>')){
$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($col, $row, $value);
}
$row++;
If this isn't what you were looking for, then please provide a sample input that can be matched to the output, as this would make what you need crystal clear.
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 "£".