How to change the search query from AND to OR in Opencart? - opencart

Opencart: v.1.5.6.4
When someone searches for "iphone nikon" in Opencart's search input text field the results are:
"There is no product that matches the search criteria." (example - https://o-v156x.my-soul.net/index.php?route=product/search&search=iphone%20nikon)
What I want to achieve is to change the search query from AND to OR to get results:
iphone
Nikon D300
or all the products where these words appear in product's name.
I am not interested in live search (auto-complete or auto-suggest or auto-correct).
I am pretty sure that the changes I want to make (by using vQmod) are inside the file /catalog/model/catalog/product.php.
Where exactly is the code needed to be changed?

EDIT
catalog/model/catalog/product.php
Locate the function getProducts()
Find the following code block in relevant function:
foreach ($words as $word) {
$implode[] = "pd.name LIKE '%" . $this->db->escape($word) . "%'";
}
if ($implode) {
$sql .= " " . implode(" AND ", $implode) . "";
}
and replace the code block with:
foreach ($words as $word) {
$implode[] = "pd.name LIKE '%" . $this->db->escape($word) . "%'";
}
if ($implode) {
$sql .= " " . implode(" OR ", $implode) . "";
}
Find the following code inside the getTotalProducts() function
foreach ($words as $word) {
$implode[] = "pd.name LIKE '%" . $this->db->escape($word) . "%'";
}
if ($implode) {
$sql .= " " . implode(" AND ", $implode) . "";
}
and replace with following
foreach ($words as $word) {
$implode[] = "pd.name LIKE '%" . $this->db->escape($word) . "%'";
}
if ($implode) {
$sql .= " " . implode(" OR ", $implode) . "";
}
Hope it helps, CHEERS!

Look for the function called getProducts() in the file /catalog/model/catalog/product.php. Within this look for something similar to the following line which deals with the variable filter_name
if ($implode) {
$sql .= " " . implode(" AND ", $implode) . "";
}
You will have to change the AND to OR in the above statement, but remember if you make this change in the core any updates to OpenCart will change this back to what the update is.

Related

-E parameter exclude the string from result

We are trying to create regex for the following string:-
$last_id . ' where ticket_id=' . $this->getId() {
to test our regex we wrote the following bash one line:-
echo " $last_id . ' where ticket_id=' . $this->getId() {"| grep -i -E ".*(:?.*\$*.WHERE.*) " --color=auto;
The result is:-
. ' where ticket_id=' . ->getId() {
expected result:-
. ' where ticket_id=' . $this->getId() {
But the -E parameter excludes $this. Please help we are stuck.
Your $this gets dropped out before reaching grep, because it's being expanded by shell as a variable named this.
See:
$ echo " $last_id . ' where ticket_id=' . $this->getId() {"
. ' where ticket_id=' . ->getId() {
To prevent parameter expansion in shell, just escape the $:
echo " \$last_id . ' where ticket_id=' . \$this->getId() {"
$last_id . ' where ticket_id=' . $this->getId() {

How to limit my regex that is detecting too much?

I have a regex that is attempting to detect title & link markup:
[title](http://link.com)
So far I have:
(\[)(.*?)(\])(\(((http[s]?)|ftp):\/\/)(.*?)(\))
Which is detecting to much when an untitled link markup is before it
[http://google.com] [Digg](http://digg.com)
[Internal Page] Random other text [Digg](http://digg.com)
How can I limit the regex to just the titled link?
Full PHP for titled & untitled links:
// Titled Links
// [Digg](http://digg.com)
// [Google](http://google.com)
$text = preg_replace_callback(
'/(\[)(.*?)(\])(\(((http[s]?)|ftp):\/\/)(.*?)(\))/',
function ($match) {
$link = trim($match[7]);
$ret = "<a target='_blank' href='" . strtolower($match[5]) . "://" . $link . "'>" . trim($match[2]) . "</a>";
if (strtolower($match[5]) == "http") {
$ret .= "<img src='/images/link_http.png' class='link' />";
} else if (strtolower($match[5]) == "https") {
$ret .= "<img src='/images/link_https.png' class='link' />";
} else if (strtolower($match[5]) == "ftp") {
$ret .= "<img src='/images/link_ftp.png' class='link' />";
}
return $ret;
},
$text
);
// Untitled Links
// [Internal Page]
// [http://google.com]
$text = preg_replace_callback(
'/(\[)(.*?)(\])/',
function ($match) {
$link = trim($match[2]);
$ret = "";
if ($this->startsWith(strtolower($link), "https")) {
$ret = "<a target='_blank' href='" . $link . "'>" . $link . "</a>";
$ret .= "<img src='/images/link_https.png' class='link' />";
} else if ($this->startsWith(strtolower($link), "http")) {
$ret = "<a target='_blank' href='" . $link . "'>" . $link . "</a>";
$ret .= "<img src='/images/link_http.png' class='link' />";
} else if ($this->startsWith(strtolower($link), "ftp")) {
$ret = "<a target='_blank' href='" . $link . "'>" . $link . "</a>";
$ret .= "<img src='/images/link_ftp.png' class='link' />";
} else {
$link = str_replace(" ", "_", $link);
$ret = "<a href='" . $link . "'>" . trim($match[2]) . "</a>";
}
return $ret;
},
$text
);
If you're trying to go through Markdown links, you'll probably want to grab the regex and logic straight from the source:
https://github.com/michelf/php-markdown/blob/lib/Michelf/Markdown.php#L510
https://github.com/tanakahisateru/js-markdown-extra/blob/master/js-markdown-extra.js#L630
Make the title optional by appending a '?' to the group that matches the title.
Instead of (.*?) try matching on something you really don't want, like a space e.g. ([^\s]+).
Also, the whole of the second part is optional (if you can have a untitled link), so add the ? as #Arnout suggests, e.g.
(\(((http[s]?)|ftp):\/\/)([^\s]+)(\))?
May I also suggest, (though I'm not sure it's supported in PHP regex it appears to be, using the whitespace flag and breaking it up over a few lines for readability:
/
(
\[
)
(.*?)
(
\]
)
(
\(
(
(http[s]?)
|
ftp
)
:\/\/
)
(.*?)
(
\)
)
/x
That is a lot clearer, and it's easier to see:
The [s]? could just be s?
The scheme brackets should be ((?:https?)|(?:ftp)) or it only ORs on the f, and you get additional unneeded captures.
You may possibly be able to comment on it too, within the regex (again, I'm unsure you can with PHP).
This works but doesn't have the parentheses for all the groups you're trying to match.
\[[\w\s]+\]\((https?|ftp)://[^)]+\)

Use Perl to search for a match between two files

I have two files: file1.txt and file2.txt. Both contains lines in this format:
file1
name1:value1
file2
name2:value2
I want to check if value1 is found in list2 (in the name2 string)
I have this function:
#!/usr/bin/perl
use warnings;
use Parallel::ForkManager;
sub loadf($);
print "Starting main program\n";
my #list1 = loadf("list1.txt");
my #list2 = loadf("list2.txt");
my $workernum = 10;
open(OK, '>>', 'valid.txt');
open(ER, '>>', 'invalid.txt');
$pm = new Parallel::ForkManager($workernum);
my $cnt = 0;
foreach $line (#list1) {
$cnt++;
my $pid = $pm->start and next;
my #data1 = split(":", $line);
my $name1 = $data1[0];
my $value1 = $data1[1];
my #data2 = split(":", $list2);
my $name2 = $data2[0];
my $value2 = $data2[1];
if (/$value1/i ~~ #list2)
{
print OK $name1 . " - " . $value2 . "\n";
print " [+] Found: " . $name1 . " - " . $value2 . "\n";
}
else
{
print ER $name1 . "\n";
print " [x] Unknown: " . $name1 . " - " . $value1 . "\n";
}
$pm->finish;
}
close(OK);
close(ER);
print "\n*** Finished ***\n";
sub loadf($) {
my #file;
open(FILE, $_[0] . "\n") or die("[+] Couldn't open " . $_[0] . "\n");
#file = <FILE>;
close(FILE);
return #file;
}
__END__
which is not working. What am I doing wrong ?
#!/usr/bin/perl
open(F,'list1.txt');
my #list1=<F>;
close(F);
open(F,'list2.txt');
my #list2=<F>;
close(F);
chomp(#list1,#list2);
foreach my $line (#list1)
{
if ($line=~/.+\:.+/)
{
my #data1 = split(":", $line);
if (my #d2=grep /$data1[1]\:/i,#list2){print " [+] Found: " . $data1[0] . " - " . [split(':',$d2[0])]->[1] . "\n"; }
else { print " [x] Unknown: " . $data1[0] . " - " . $data1[1] . "\n"; }
}
}
Erm... I really don't get your algorithm, sorry. First you read all the lines from compared files into two arrays, then you forking the processor loop but, as I see it, make no attempts to split these workers' job into chunks (to parallel it).
I'd suggest trying a bit different approach: slurp only the second file, then process the first file line by line. You didn't mention whether names and values of the second file are unique; I suppose they're not, but the program could be made even simpler if they are.
open my $caf, '<', 'list2.txt' or die $!, "\n";
my $checkedAgainst = do { local $/; <$caf>; };
open my $cf, '<', 'list1.txt' or die $!, "\n";
my $workernum = 10;
$pm = new Parallel::ForkManager($workernum);
while (<$cf>) {
my $pid = $pm->start and next;
my ($nameToCheck, $valueToCheck) = split /:/;
if ($checkedAgainst =~ /^\Q$valueToCheck\E:(.+)$/m) {
print " [+] Found: $nameToCheck - $1", "\n";
}
else {
print " [x] Unknown: $nameToCheck - $valueToCheck", "\n";
}
}
$pm->finish;
In other words, I first load the second file into one big string, then try to match it with the lines from the first file (line by line). I don't know, what symbols could appear in your values, that's why \Q-\E (quotemeta operators) are used there.
UPDATE: attempted to make this code fork, have no means to test it where I stand though.

(La)Tex math parsing for C/C++

I would like to convert parse (la)tex math expressions, and convert them to (any kind of!) scripting language expression, so I can evaluate expressions.
What libraries do you recommend ?
May be it will help - take a look at TeXmacs, especially at a way it interacts with computer algebra systems.
Here is a set of possible options from a similar question. https://tex.stackexchange.com/questions/4223/what-parsers-for-latex-mathematics-exist-outside-of-the-tex-engines
I think that Perl would make a fine choice for something like this, acting on text is one of its fortes.
Here is some info on how to make an exclusive flip-flop test (to find the context between \begin{} and \end{} without keeping those lines), http://www.effectiveperlprogramming.com/2010/11/make-exclusive-flip-flop-operators/
EDIT: So this problem has started me going. Here is a first attempt to create something here is my "math.pl" which takes a .tex file as an arguement (i.e. $./math.pl test.tex).
#!/usr/bin/env perl
use strict;
use warnings;
use Text::Balanced qw/extract_multiple extract_bracketed/;
my $re_num = qr/[+\-\dE\.]/;
my $file = shift;
open( my $fh, '<', $file);
#parsing this out for more than just the equation environment might be easier using Text::Balanced too.
my #equations;
my $current_equation = '';
while(<$fh>) {
my $test;
next unless ($test = /\\begin\{equation\}/ .. /\\end\{equation\}/);
if ($test !~ /(^1|E0)$/ ) {
chomp;
$current_equation .= $_;
} elsif ($test =~ /E0$/) {
#print $current_equation . "\n";
push #equations, {eq => $current_equation};
$current_equation = '';
}
}
foreach my $eq (#equations) {
print "Full Equation: " . $eq->{'eq'} . "\n";
solve($eq);
print "Result: " . $eq->{'value'} . "\n\n";
}
sub solve {
my $eq = shift;
print $eq->{'eq'} . "\n";
parse($eq);
compute($eq);
print "intermediate result: " . $eq->{'value'} . "\n";
}
sub parse {
my $eq = shift;
my ($command,#fields) = extract_multiple(
$eq->{'eq'}, [ sub { extract_bracketed(shift,'{}') } ]
);
$command =~ s/^\\//;
print "command: " . $command . "\n";
#fields = map { s/^\{\ *//; s/\ *\}$//; print "arg: $_\n"; {value => $_}; } #fields;
($eq->{'command'}, #{ $eq->{'args'} }) = ($command, #fields);
}
sub compute {
my ($eq) = #_;
#check arguements ...
foreach my $arg (#{$eq->{'args'}}) {
#if arguement is a number, continue
if ($arg->{'value'} =~ /^$re_num$/) {
next;
#if the arguement is a simple mathematical operation, do it and continue
} elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\ |\*|\\times)?\ *($re_num)$/) {
$arg->{'value'} = $1 * $2;
} elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\+)?\ *($re_num)$/) {
$arg->{'value'} = $1 + $2;
} elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\-)?\ *($re_num)$/) {
$arg->{'value'} = $1 - $2;
} elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\/)?\ *($re_num)$/) {
$arg->{'value'} = $1 / $2;
} else {
#parse it and calc it as if it were its own equation.
$arg->{'eq'} = $arg->{'value'};
solve($arg);
}
}
my #args = #{$eq->{'args'}};
## add command processing here
# frac
if ($eq->{'command'} eq 'frac') {
$eq->{'value'} = $args[0]->{'value'} / $args[1]->{'value'};
return;
}
}
and here is a sample test.tex:
\documentclass{article}
\begin{document}
Hello World!
\begin{equation}
\frac{\frac{1}{3}}{2}
\end{equation}
\end{document}
Maybe using boost::spirit in order to tokenize the expression. You will need to define a huge grammar!
Use a parser generator to create an appropriate parser. Try ANTLR for this, as it includes an IDE for the Grammar, which is very helpful. Using tree rewrite rules, you can then convert the parse tree to an abstract syntax tree.
Start perhaps with the expression evaluator from ANTLR tutorial. I think this is reasonably close enough.

How to do perl inline regex without setting to a variable?

Normally if you wish to change a variable with regex you do this:
$string =~ s/matchCase/changeCase/;
But is there a way to simply do the replace inline without setting it back to the variable?
I wish to use it in something like this:
my $name="jason";
print "Your name without spaces is: " $name => (/\s+/''/g);
Something like that, kind of like the preg_replace function in PHP.
Revised for Perl 5.14.
Since 5.14, with the /r flag to return the substitution, you can do this:
print "Your name without spaces is: [", do { $name =~ s/\s+//gr; }
, "]\n";
You can use map and a lexical variable.
my $name=" jason ";
print "Your name without spaces is: ["
, ( map { my $a = $_; $a =~ s/\s+//g; $a } ( $name ))
, "]\n";
Now, you have to use a lexical because $_ will alias and thus modify your variable.
The output is
Your name without spaces is: [jason]
# but: $name still ' jason '
Admittedly do will work just as well (and perhaps better)
print "Your name without spaces is: ["
, do { my ( $a = $name ) =~ s/\s+//g; $a }
, "]\n";
But the lexical copying is still there. The assignment within in the my is an abbreviation that some people prefer (not me).
For this idiom, I have developed an operator I call filter:
sub filter (&#) {
my $block = shift;
if ( wantarray ) {
return map { &$block; $_ } #_ ? #_ : $_;
}
else {
local $_ = shift || $_;
$block->( $_ );
return $_;
}
}
And you call it like so:
print "Your name without spaces is: [", ( filter { s/\s+//g } $name )
, "]\n";
print "Your name without spaces is: #{[map { s/\s+//g; $_ } $name]}\n";