0

Ok, I know similar questions have been asked before but none of the answers I found seem to work. Here's my code:

$sql = $wpdb->prepare('SELECT ID FROM ' . $ignore_url_table_name . " where url LIKE '%%%s%%'", $urlRequested);
$wpdb->get_row($sql);
if ($wpdb->num_rows > 0) {
    return;
}

Here's the problem: I'm trying to detect when a specific string is found in the URL. One example of the url in the talble to look for is:

doing_wp_cron

An example of the $urlRequested is:

doing_wp_cron=1543678213.5953478813171386718750

The above SQL statement doesn't find a match.

I've also attempted to use

$sql = $wpdb->prepare('SELECT ID FROM ' . $ignore_url_table_name . " where url LIKE '%s'", '%' . $wpdb->esc_like($urlRequested) . '%');

This appears to turn the doing_wp_cron into doing//_wp//_cron which the query also doesn't find.

What am I doing wrong here?

Thanks

*Edit: So I echoed out the sql query and this looked strange.

SELECT ID FROM URL_Ignores where url LIKE '{1b71fb783b53a0ae087bf6ac6b01addd9b80435193728fe4c7c7d70b30748268}/doing_wp_cron=1543682280.1607289314270019531250{1b71fb783b53a0ae087bf6ac6b01addd9b80435193728fe4c7c7d70b30748268}'

I have no idea why but it seems every way I try to $wpdb->prepare this it's converting the % into a random variable!???

1
  • Keep in mind that the doing_cron= always has a random number on the end, it's never the same, and so it will never match anything in your database because every time it's unique. If your goal is to not run when cron is running, I don't think a database query is really the best solution
    – Tom J Nowell
    Commented Dec 1, 2018 at 19:40

2 Answers 2

1

Well, since I haven't used a LIKE in a plugin in a while, it seems I missed this one.

WP is now adding 'placeholders' whenever you prepare or esc a query. The short solution I found was to do this. It may not be the proper one, but it works.

$sql = $wpdb->remove_placeholder_escape($wpdb->prepare("SELECT ID FROM $ignore_url_table_name where '%s' LIKE CONCAT('%',url,'%')",$urlRequested));
2
  • is this workaround safe? Commented May 31, 2021 at 13:14
  • I ended up doing this which I assume is about as safe as it gets. $urlRequested = strip_tags( stripslashes( filter_var($urlRequested, FILTER_VALIDATE_URL) ) );
    – uPrompt
    Commented Jun 1, 2021 at 15:12
1

There are several things going on here

Misuse of $wpdb->prepare

This is a very strange way to use prepare:

$sql = $wpdb->prepare('SELECT ID FROM ' . $ignore_url_table_name . " where url LIKE '%%%s%%'", $urlRequested);

In particular, instead of %s you have '%%%s%%', which is very unusual. prepare expects %s, and will insert quotes for you as it is aware already that it is a string. Additionally, although it bears similarities to sprintf, it is not sprintf and does not function quite the same. Type casting, sanitising, and escaping etc are being applied. This is a security function, not a simple string manipulation function.

For example, this:

$sql = $wpdb->prepare('%s %s', 'hello', 'world' );

results in:

"hello" "world"

WP Cron

You will never find the URL you gave as an example in your database table. This is because doing_cron always has a different value afterwards, so it will not be present in your table. If you put it in your table it won't work either because it will never appear a second time.

Instead, the solution is to realise that this approach is completely incorrect for some situations, and that this would have been a better solution:

if ( wp_doing_cron() ) {
    return;
}

Similarly wp_doing_ajax should be checked, and you might want to catch the REST API and RSS feeds, but because you never provided context to your question and what the purpose of your URL detection is for, I can't comment further

3
  • Yes, I realized in my first post that I had the query reversed. Here's the problem. both wpdb->prepare and esc_url now add in placeholders. In doing so, it converts all % to a huge random number. When I tried passing a query with the placeholders it simply wasn't finding the results it should.
    – uPrompt
    Commented Dec 1, 2018 at 20:34
  • The whole purpose of this is to log incoming URL's. This query checks them against a whitelist to ignore, of which, wp_doing_cron is one. loggedout=true would be another. The answer I posted does find the wp_doing_cron if it's in the url. Whether is properly sanitized is another question. I did esc_url to try to make sure.
    – uPrompt
    Commented Dec 1, 2018 at 20:42
  • esc_url is an escaping function, not a sanitising function. It will always return a URL, even if it has to mangle the data to make it fit. It should be used on output not here, wpdb prepare will handle any sanitising needed to prevent SQL injection if used correctly. I'd strongly recommend removing esc_url. Sanitize on input, validate before use/save, escape on output
    – Tom J Nowell
    Commented Dec 1, 2018 at 21:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.