Preg_match with different combinations of words - php

I've a littile question about preg_matches, these regex things are really hard to understand and I hope someone can give the right awnser!
I have the following text:
0A-24-423
But this can also be:
0A-242-2
or
0A-2-423
How can I use preg_matches to filter these? I was using
substr($something, 0,2)
so that it captures 0A and
substr($seat, 4,5)
This will capture 24 but when you get 242 it wont capture the last 2....
Hope someone can help creating this in preg_match!
to make it more clear what I have now:
foreach($_POST['seats'] AS $seat) {
if ($count > 0) {
$selectQuery .= " || ";
}
$selectQuery .= " ( rowId = '" . substr($seat, 0,2) . "'";
$selectQuery .= " and `order` = " . substr($seat, 3,5) . " ";
$selectQuery .= " and columnId = " . substr($seat, 6) . " ) ";
$count++;
and $seat had the following format XXXXXX and using substr I can get the right things (for example: 0J3017)
Something Like this should do it:
$selectQuery = "SELECT * from seats where ";
$count = 0;
$pattern = "I DON'T KNOW :( ";
foreach($_POST['seats'] AS $seat) {
if ($count > 0) {
$selectQuery .= " || ";
}
preg_match($pattern, $seats, $matches);
$selectQuery .= " ( rowId = '" . $matches[0] . "'";
$selectQuery .= " and `order` = " . $matches[1] . " ";
$selectQuery .= " and columnId = " . $matches[2] . " ) ";
$count++;
and $seats is explained in the beginning of the post (it has a format of XX-XXX-XXX
where the first 2 XX are 0[A-Z] (yes the 0 is correct)
where the 3 first XXX are [0-9]
Where the last 3 XXX are [0-9]
EDIT:
there are 2 ways to solve this.
Option 1:
$pattern = "/(.*)-(.*)-(.*)/";
or use explode() function.

It does not look like you need to be using regular expressions. Here's an example using explode() and list():
list($row_id, $order, $column_id) = explode('-', $seat, 3);
You could then use those three new variables in your $selectQuery.

EDIT : Since the OP has stated his requirement as a comment to my answer I have updated my answer accordingly.
You can try this:
$pattern = "/[A-Z\d]{1,2}-[A-Z\d]{1,3}-[A-Z\d]{1,3}/";
$matched = preg_match($pattern, $something);
if ($matched === 0) {
die('regex did not match');
}
$matched will give you 1 for a matched string and 0 if not matched.

Related

Showing a limited number of mysqli_fetch_assoc array

I want to create an array with the help of MYSQL and display it the following way:
while ($array = mysqli_fetch_assoc($res))
{
echo $array["first_name"] . ", "
. $array["last_name"] . ", "
. $array["personal_id"] . ", "
. $array["salary"] . ", "
. $array["birthday"] . "<br />";
}
To improve usability, I only want to display 10 results, put a link to the next 10 results at the bottom and display these on another page.
How do I have to change the while-condition in order to only display the first 10 results of my result?
I tried searching for a solution but I couldn't find anything that fits my needs, so any help is appreciated!
Thanks in advance!
Check offset and limit conditions in mysql.
Example: to show 16 - 26 records from result query.
$sql = "SELECT * FROM Table LIMIT 10 OFFSET 15"
If what you want is just a way to break out of the loop after the first 10 results.
$counter = 1;
while (($array = mysqli_fetch_assoc($res)) || ($counter < 10))
{
echo $array["first_name"] . ", "
. $array["last_name"] . ", "
. $array["personal_id"] . ", "
. $array["salary"] . ", "
. $array["birthday"] . "<br />";
$counter++;
}

PHP While Loop In a While Loop

Trying to run a script to email users their individual schedules from my database.
The code should go like this...select all users from Table 1 where users want their weekly email.
Then take those user_ids and run a query to obtain the weekly schedules for each user from Table 2.
If the date in the Table 2 is less than or equal to 1 week from when the code is ran, and it does not equal today's date, then set the variable $email_content.
If the date in the Table 2 exceeds 1 week, then the code should know that it is done, and here is would like to go ahead and mail() the info gathered for that user and send only that info, to only that user, then continue on to the next user.
Where it says echo "break", it is essentially marking the separation between each users' schedule, but it is echoing about 20 times. This part will ideally become where I put the mail() function, so I can't have it execute the mail() function 20 times too.
I've tried a ton of different variations of this code, but can't seem to get it right. To summarize, I need to get info1 for user1, then mail info1 to user1, then move on to get info2 for user2, then mail info2 to user2, etc...
<?php
// GET USERS WHO WANT THEIR WEEKLY SCHEDULE EMAILED TO THEM (Table 1)
$sql = "SELECT * FROM XXXXXXX WHERE weekly_email = 'Yes'";
$result = mysqli_query($connection, $sql);
while ($row = mysqli_fetch_array($result)) {
$id .= "'" . $row['user_id'] . "', ";
}
$id = trim($id, ', ');
// GET THOSE USERS' SCHEDULES (Table 2)
$sql_email = "SELECT * FROM XXXXXXXX WHERE user_id IN ($id) ORDER BY user_id, date, start_time ASC";
$result_email = mysqli_query($connection, $sql_email);
while ($row_email = mysqli_fetch_array($result_email)) {
$truck_name_email = $row_email['truck_name'];
$location_name_email = $row_email['location_name'];
$date_email = $row_email['date'];
$address_email = $row_email['address'];
$x = strtotime("7 days");
$start_email = $row_email['start_time'];
$end_email = $row_email['end_time'];
if ($date_email <= date("m/d/Y l", $x)) {
if ($date_email !== date("m/d/Y l")) {
if (!empty($address_email)) {
$address_email2 = explode(",", $row_email['address'], 2);
$email_content = $date_email . substr($date_email, 11) . " - "
. $location_name_email . ", " . $address_email2[0] . ", "
. $start_email . "-" . $end_email . "<br/>";
echo $email_content;
} elseif (empty($address_email)) {
$email_content .= $date_email . " - " . $location_name_email
. ", " . $start_email . "-" . $end_email . "<br/>";
echo $email_content;
}
}
}
if ($date_email >= date("m/d/Y l", $x)) {
echo "break";
// break;
}
}
Just saying that you should pay attention to potential SQL injection, escape any user-controllable strings before they get in the SQL statement. For example if $row['user_id'] is a string then you must perform mysqli_escape_string
Seems like that you forgot something in your code:
$x = strtotime("7 days");
$start_email = $row_email['start_time'];
$end_email = $row_email['end_time'];
if ($date_email <= date("m/d/Y l", $x)) {
if ($date_email !== date("m/d/Y l")) { // I think that you have a $x here?
if (!empty($address_email)) {
$address_email2 = explode(",", $row_email['address'], 2);
$email_content = $date_email . substr($date_email, 11) . " - "
. $location_name_email . ", " . $address_email2[0] . ", "
. $start_email . "-" . $end_email . "<br/>";

MySQL/PHP mysql_fetch_array() keeps missing first row

Good eve everyone!
For some reason Database::fetchArray() is skipping the first $row of the query result set.
It prints all rows properly, only keeps missing out the first one for some reason, I assume there's something wrong with my fetchArray() function?
I ran the query in phpMyAdmin and it returned 4 rows, when I tried it on my localhost with the php file (code below) it only printed 3 rows, using the same 'WHERE tunes.riddim'-value ofcourse. Most similiar topics on google show that a common mistake is to use mysql_fetch_array() before the while(), which sets the pointer ahead and causes the missing of the first row, unfortunately I only have one mysql_fetch_array() call (the one within the while()-head).
<?php
$db->query("SELECT " .
"riddims.riddim AS riddim, " .
"riddims.image AS image, " .
"riddims.genre AS genre, " .
"tunes.label AS label, " .
"tunes.artist AS artist, " .
"tunes.tune AS tune, " .
"tunes.year AS year," .
"tunes.producer AS producer " .
"FROM tunes " .
"INNER JOIN riddims ON tunes.riddim = riddims.riddim " .
"WHERE tunes.riddim = '" . mysql_real_escape_string(String::plus2ws($_GET['riddim'])) . "'" .
"ORDER BY tunes.year ASC");
$ar = $db->fetchArray();
for($i = 0; $i < count($ar) - 1; $i++)
{
echo $ar[$i]['riddim'] . " - " . $ar[$i]['artist'] . " - " . $ar[$i]['tune'] . " - " . $ar[$i]['label'] . " - " . $ar[$i]['year'] . "<br>";
}
?>
Database::fetchArray() looks like:
public function fetchArray()
{
$ar = array();
while(($row = mysql_fetch_array($this->result)) != NULL)
$ar[] = $row;
return $ar;
}
Any suggestions appreciated!
You should remove -1 from the for loop
The problem's in your while loop:
for($i = 0; $i < count($ar) - 1; $i++)
if count ($ar) is 1, because there's one entry, your loop will never be called; try tweaking the check part:
for($i = 0; $i < count($ar) ; $i++)
You can also use a simple foreach:
foreach($db->fetchArray() as $row)
{
echo $row['riddim'] # ...
}
It'll make your code more readable too.

Finding matches between two tables, each with 160k+ rows

I have two tables each with 160k+ rows each. between the two some UUID are shared. I'm and using a foreach loop over the "new" table with an embedded foreach searching the "old" table. When a UUID match is out the "old" table is updated with data from the "new" table.
Both tables have an index on the ID.
My problem is this operation is extreme time intensive; does anyone know a more efficient way to do said search for matching UUIDs? Sidenote: we are using the MySQLi extension for PHP 5.3
Exp code:
$oldCounter = 0;
$newCounter = 1;
//loop
foreach( $accounts as $accKey=>$accValue )
{
echo( "New ID - " . $oldCounter++ . ": " . $accValue['id'] . "\n" );
foreach( $accountContactData as $acdKey=>$acdValue )
{
echo( "Old ID - " $newCounter++ . ": " . $acdValue['id'] . " \n" );
if( $accValue['id'] == $acdValue['id'] && (
$accValue['phone_office'] == "" || $accValue['phone_office'] == NULL || $accValue['phone_office'] == 0 )
){
echo("ID match found\n");
//when match found update accounts with accountsContact info
$query = '
UPDATE `accounts`
SET
`phone_fax` = "' . $acdValue['fax'] . '",
`phone_office` = "' . $acdValue['telephone1'] . '",
`phone_alternate` = "' . $acdValue['telephone2'] . '"
WHERE
`id` = "' . $acdValue['id'] . '"
';
echo "" . $query . "\n\n";
$DB->query($query);
break 1;
}
}
}
unset($oldCounter);
unset($newCounter);
Thank you in advance.
Do this all in SQL.
There is nothing that I see in your code that requires PHP.
UPDATE allows JOIN. JOIN the new and old tables and have your WHERE conditions match that of your description. Should be pretty straightforward and significantly faster.
I wrote a function some months ago
You can modify it as you want .
This can improve the speed of your search
public static function search($query)
{
$result = array();
$all = custom_query::getNumRows("bar");
$quarter = floor(0.25 * $all) + 1;
$all = 0;
for($i = 0;$i<4;$i++)
{
custom_query::condition("", "limit $all, $quarter");
$data = custom_query::FetchAll("bar");
foreach ($data as $v)
foreach($v as $_v)
if (count(explode($query, $_v)) > 1)
$result[] = $v["bar_id"];
$all += $quarter;
}
return $result;
}
It returns you the ID of the record that search matched on it.
This method divides the table to 4 parts and each iteration gets only a quarter of it...
You can change this number to for example 10 or 20 for speed of...
some methods are in the class and you can easily write theme...

Problems using GROUP BY in MySQL in a query that does a JOIN on two tables

I have two MySQL tables, $database1 and $database2. Both have a field in them called ID. I am passing the name of a town to the file using GET (i.e. it's in the URL of the PHP file that holds this code).
I can run this query...
$PlaceName = $_GET['townName'];
$PlaceName = mysql_real_escape_string($PlaceName);
$sql="SELECT * from $database1 LEFT JOIN $database2 on $database1.ID = $database2.ID WHERE PlaceName='$PlaceName'";
$query = mysql_query($sql);
echo '<h1>People who are searching for '.$PlaceName.':</h1>';
echo '<ul>';
while ($row = mysql_fetch_array($query)) {
echo "<li>ID #",$row['ID'],": ",$row['MemberPersonalName']," ",$row['MemberSurname']," -- searching for ",$row['SurnameBeingSearched'],"</li>";
}
echo '</ul>';
...and it works and all is well. Right now the output looks like this...
People who are searching for Hogwarts:
ID #137: Hermione Granger -- searching for Stern
ID #137: Hermione Granger -- searching for Engelberg
ID #503: Harry Potter -- searching for Kreindler
ID #549: Ron Weasley -- searching for Kreindler
ID #1062: Draco Malfoy -- searching for Engelberg
ID #1155: Ginny Weasley -- searching for Kreindler
ID #1155: Ginny Weasley -- searching for Streisand
But the output needs tweaking, and I'm having trouble writing my SQL query statement to reflect the changes. What I really want is for the output to look like this...
People who are searching for Hogwarts:
Engelberg is being searched by Hermione Granger (id #137) and Draco Malfoy (id #1062)
Kreindler is being searched by Harry Potter (id #503), Ron Weasley (id #549), and Ginny Weasley (id #1155)
Stern is being searched by Hermione Granger (id #137)
Streisand is being searched by Ginny Weasley (id #1155)
In other words, I need to group the output together by the field 'SurnameBeingSearched', I need to list the names of the people doing the searching in an "X, Y, and Z" output format (where it knows where to add a comma, if necessary, depending on the number of results), and I need to order the results by the 'SurnameBeingSearched' field.
Help? Thanks!
You need to list the names so this isn't an aggregation (in the SQL sense) problem. Keep your current query. You're going to have to do the grouping in code.
So something like:
$rows = array();
$last = '';
while ($row = mysql_fetch_array($query)) {
$surname = $row['SurnameBeingSearched'];
$id = $row['ID'];
$name = $row['MemberPersonalName'];
if ($last != $surname) {
$last = $surname;
$rows[] = array();
}
$rows[count($rows)-1][$id] = $name;
}
foreach ($rows as $row) {
// now display each group of names
}
You might also be able to use the MySQL GROUP_CONCAT() function.
It would look something like this...
SELECT places_tbl.name, GROUP_CONCAT(people_tbl.name)
FROM places_tbl
LEFT JOIN people_tbl ON (places_tbl.id = people_tbl.id)
GROUP BY places_tbl.id
GROUP_CONCAT() by default returns the values as comma delimited. You can probably split them up to get the formatting as you need it or use the SEPARATOR keyword. GROUP_CONCAT(fieldname SEPARATOR '-')
$PlaceName = $_GET['townName'];
$PlaceName = mysql_real_escape_string($PlaceName);
// note - added order to the query
$sql="SELECT * from $database1 LEFT JOIN $database2 on $database1.ID = $database2.ID WHERE PlaceName='$PlaceName'
ORDER BY SurnameBeingSearched, MemberSurname, MemberPersonalName";
$query = mysql_query($sql);
echo '<h1>People who are searching for '.$PlaceName.':</h1>';
echo '<ul>';
$cntr = mysql_num_rows($query);
if ($cntr > 0) {
$i = 0;
$srchd = mysql_result($query, $i, 'SurnameBeingSearched');
$mbr = mysql_result($query, $i, 'MemberPersonalName');
$mbr = $mbr . " " . mysql_result($query, $i, 'MemberSurname');
$mbr = $mbr . " (id #" . mysql_result($query, $i, 'ID') . ")";
$lin = $srchd . " is being searched by " . $mbr;
$prev = $srchd;
if ($cntr == 1) {
echo "<li>" . $lin . "</li>";
} else {
for ($i = 1; $i< $cntr; $i++) {
$srchd = mysql_result($query, $i, 'SurnameBeingSearched');
$mbr = mysql_result($query, $i, 'MemberPersonalName');
$mbr = $mbr . " " . mysql_result($query, $i, 'MemberSurname');
$mbr = $mbr . " (id #" . mysql_result($query, $i, 'ID') . ")";
if ($srchd == $prev) { // common search
$j = $i + 1;
if ($j < $cntr) { // still have data
$nxt = mysql_result($query, $j, 'SurnameBeingSearched');
if ($prev == $nxt) { // another one coming -- use the comma
$lin = $lin . ", " . $mbr;
} else {
$lin = $lin . ", and " . $mbr; // last member add the 'and' - line is done
echo "<li>" . $lin . "</li>";
}
$prev = $srchd;
} else { // ran out of data - need to finish the line
$lin = $lin . ", and " . $mbr; // last member add the 'and' - line is done
echo "<li>" . $lin . "</li>";
} else { // new search - need to print this line and start a new one
echo "<li>" . $lin . "</li>";
$lin = $srchd . " is being searched by " . $mbr;
$prev = $srchd;
} // test searched = previous
} // next i
} // only one row
} // cntr > 0
echo '</ul>';
/* note: this is not tested
I would recommend using table1 and table2 instead of database1 and database2
or better give the tables meaningful names
I would use active voice instead of passive voice
*/

Categories