-3

[EDIT] I am placing the comment I entered near the bottom of this post to, hopefully avoid further down votes. This was a pretty basic question stemming from my misunderstanding of what exactly $_REQUEST is. My understanding was that it was an index that referenced $_POST and $_GET (and $_COOKIE). However, I found that $_REQUEST is, itself, an array, so I simply changed the variables in $_REQUEST. Not an optimal solution, but a solution, nonetheless. It has the added advantage that the $_GET variables, with the apostrophes still there, are available. Perhaps not the best practice, but please note before you down vote that I have very little control over this data - coming in from one API and going out to another.

I have an API currently in use. We have a problem with some customers sending apostrophes in the URL. My question is how best to strip the apostrophes within the URL array. Perhaps using array_walk or something similar?

So that $_REQUEST[Customer] == "O'Henry's"
Becomes $_REQUEST[Customer] == "OHenrys"

EDIT: Judging from some of the answers here, I believe I need to explain a little better. This is an API that is already written and is the preliminary interface for another AS400 API. I have nothing to do with building the URL. I am receiving it. All I am concerned about is removing the apostrophes, without changing any other code. So the best way is to go through the array. In the body of the code, the variable references are all using $_REQUEST[]. I COULD go in and change those to $_GET[] if absolutely necessary but would rather avoid that.

This Works

foreach($_REQUEST as $idx => $val)
{
    $_REQUEST[$idx] = str_replace("'" , '' , $val);
}

However, I am a little leery of using $_REQUEST in that manner. Does anyone see a problem with that. (Replacing $_REQUEST with $_GET does not work)

RationalRabbit
  • 1,037
  • 13
  • 20
  • 3
    Why would you want to strip them? Encode it...or if this is for SQL use parameterized queries. – user3783243 Jun 22 '18 at 15:26
  • 2
    tbh, if my name was something like O'Reilly I'd get really sick of websites screwing my name up... I've linked to this before but I still think it's worth referencing from time to time: https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/ – CD001 Jun 22 '18 at 15:31
  • 1
    It sounds like your issue isn't with them sending apostrophes, the issue is you're not protecting your database or views from injections. – Devon Bessemer Jun 22 '18 at 15:38
  • This is a severe XY problem. You need to preserve the data based on the display or storage medium. – MonkeyZeus Jun 22 '18 at 15:55
  • Please see the edit to my question above. – RationalRabbit Jun 22 '18 at 16:35
  • `$_REQUEST` values may themselves be arrays. Since nothing forces them to be strings, you shouldn't rely on it. My answer below includes an array_walk_recursive example you may want to look at. Are there actually multiple variables you need to sanitize, or just one? If it's just one, check for its presence and do what you need to do rather than iterate through the whole thing. – jstur Jun 22 '18 at 17:03
  • Thanks, jstur There are several, but it probably wouldn't be a noticeable amount of time to just run through the whole array. I noticed your array_walk, which was my first thought. There again, I don't know that it is more beneficial than foreach, Please correct me if I am wrong. You confirmed my insecurities about using REQUEST. Would you suggest going through the code and changing these to GET's? Or do you have another suggestion? – RationalRabbit Jun 22 '18 at 17:11
  • @user3783243 Because that's what I need to do. – RationalRabbit Jun 22 '18 at 17:14
  • 1
    If your form produces/clients submit the following: `{"test1":"1'1","test2":["2'2","2''2"]}` then the foreach will remove the single quote from `test1` but not from the two `test2` entries. My recommendation would be to refactor the code to, as early as possible, construct a normal variable from the superglobal `$_REQUEST` (or `$_GET` or `$_POST`) and modify the code to use that normal variable. Use `array_walk_recursive` to sanitize its contents using a whitelist, not a blacklist. – jstur Jun 22 '18 at 17:45
  • It is just a standard query, Good advice, though, all the way around. These files have over 5,000 references to variables using $_REQUEST, however. Sure, I can do search/replace, but I still don't do that without verifying each change. So I just changed the $_REQUEST variables. Not optimal, but the easiest solution and move on. Thanks for your help. – RationalRabbit Jun 22 '18 at 19:49

4 Answers4

2

For some use cases, it might make sense to store a "clean" or "pretty" version of the name. In that case, you may want to standardize to a case and have a whitelist of characters rather than a blacklist consisting of just single quotes. Use a regex to enforce this, perhaps similar to this one:

preg_replace("/[^[:alnum:][:space:]]/u", '', $string);

If you do that, consider if it is necessary to differentiate between different customers named O'Henrys, O'Henry's, OHenrys, O'henry's, and so on. Make sure your constraints are enforced by the app and the database.

The array_walk_recursive function is a reasonable way to hit every item in an array:

function sanitize(&$item, $key)
{
    if (is_string($item)) {
        // apply whitelist constraints
    }
}

array_walk_recursive($array, 'sanitize');

It's hard to tell without more context, but it seems possible you may be asking the wrong question / solving the wrong problem.

Remember that you can almost always escape "special" characters and render them a non-issue.

In an HTML context where a single quote might cause problems (such as an attribute value denoted by single quotes), escape for HTML using htmlspecialchars or a library-specific alternative:

<?php
// some stuff
$name = "O'Henry's";
?><a data-customer='<?=htmlspecialchars($name, ENT_QUOTES|ENT_HTML5);?>'>whatever</a><?php
// continue

For JavaScript, encode using json_encode:

<?php
// some stuff
$name = "O'Henry's";
?><script>
    var a = <?=json_encode($name);?>
    alert(a); // O'Henry's
</script>

For SQL, use PDO and a prepared statement:

$dbh = new PDO('mysql:host=localhost;dbname=whatever', $user, $pass);
$name = "O'Henry's";
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name) VALUES (:name)");
$stmt->bindParam(':name', $name);
$stmt->execute();

For use in a URL query string, use urlencode:

<?php
// some stuff
$name = "O'Henry's";
?><a href="https://example.com/path/?var=<?=urlencode($name);?>">whatever</a><?php
// continue

For use in a URL query path use rawurlencode:

<?php
// some stuff
$name = "O'Henry's";
?><a href="https://example.com/clients/<?=rawurlencode($name);?>/reports/">whatever</a><?php
// continue

Libraries and frameworks will provide additional ways to escape things in those and other contexts.

jstur
  • 659
  • 6
  • 12
  • Thanks for spotting that. Added the `ENT_QUOTES` flag to correct (and `ENT_HTML5` just because). – jstur Jun 22 '18 at 16:53
1

If you want them removing altogether as an illegal character:

<?php foreach($myArray as $idx => $val){ 

    $myArray[$idx] = str_replace("'" , '' , $val);

 }
 ?>

However this shouldn't be your solution to SQL Inserts etc.. Better off using mysqli::real_escape_string OR prepared statements

Hudson
  • 397
  • 1
  • 12
  • I was wondering about something like just treating urldecode($_SERVER[REQUEST_URI]) as a string, but that's probably over-complicating things. – RationalRabbit Jun 22 '18 at 15:39
  • What are you planning to do with the data you are sending over? – Hudson Jun 22 '18 at 15:40
  • It's an API that is already written. That is why I am trying to deal with the issue on the URL level or - at the top of the file. – RationalRabbit Jun 22 '18 at 15:59
  • 1
    Thats fair enough, I thought you was going to insert it into a database, all it takes is a quote and a `;` to make a new query... – Hudson Jun 22 '18 at 16:01
  • This will not work if I use $_GET, so I tried replacing the apostrophe with %27, but that did not work either. I believe all variable references use $_REQUEST and that does work, but I am a little leery of that due to the nature of $_REQUEST. I was actually surprised it worked. – RationalRabbit Jun 22 '18 at 16:04
  • Actually, I do insert the URL into a table for reference, if someone has a problem we need to troubleshoot. I just use urldecode($_SERVER[REQUEST_URI]) – RationalRabbit Jun 22 '18 at 16:08
  • Submitted form data can be converted by PHP to a multidimensional array, not just a flat array (`name="somename[]"`). This may not be a concern, but the above will not deal with that scenario properly. – jstur Jun 22 '18 at 16:57
  • Yeah - no concern there. No arrays being sent. – RationalRabbit Jun 22 '18 at 17:31
0

EDIT:
Reading the edits you made on your question, the best solution for you is str_replace(). But no need to loop through your array, the 3rd parameter can be an array !
This will strip apostrophes of every item in $foo:

$foo = [
    "O'Henry's",
    "D'Angleterre"
];
$foo = str_replace("'", "", $foo);


If you really need to remove the apostrophes use str_replace():
$foo = "O'Henry's";
$foo = str_replace("'", "", $foo);
// OUTPUT: OHenrys

If you can keep them, you better encode them. urlencode() may be a way to do:

$foo = urlencode($foo);
// OUTPUT: O%27Henry%27s

If you build this URL from an array you could use http_build_query():

$foo = [
    'Customer' => "O'Henry's"
];
$foo = http_build_query($foo);
// OUTPUT: Customer=O%27Henry%27s
AymDev
  • 6,626
  • 4
  • 29
  • 52
0

This was a pretty basic question stemming from my misunderstanding of what exactly $_REQUEST is. My understanding was that it was an index that referenced $_POST and $_GET (and $_COOKIE). However, I found that $_REQUEST is, itself, an array, so I simply changed the variables in $_REQUEST. Not an optimal solution, but a solution, nonetheless. It has the added advantage that the $_GET variables, with the apostrophes still there, are available. Not the best practice, though.

RationalRabbit
  • 1,037
  • 13
  • 20