How to escape quote PHP strings generated by Delph

2019-07-21 17:23发布

问题:

My code is littered with things like this

    Write  (thePhpFile, '    echo "<option value=\"' +
                                    theControl.Name +
                                    '_selection\">" . $' +
                                     theControl.Name +
                                     '_values[$_POST["' +
                                      theControl.Name +
                                      '_selection"]];');

which genrates the following PHP code

 echo "<option value=\"ComboBox1_selection\">" . 
                      $ComboBox1_values[$_POST["ComboBox1_selection"]];?>

Surely there's a better way to handle this? Maybe a Delphi function which I can pass the desired PHP string and have it double up quotes where necessary? Or am I deluding myself?

The basic algorithm would seem to be

// assume all PHP strings are double quoted, even when it's inefficient
find the first double quote, if any
find the last double quote, if any  
for every double quote in between
   change it to \""

Does that sound right? Maybe I should code it myself?

Hmmm, not so easy ... in the snippet above, we wouldn't want to escape $_POST["ComboBox1_selection"] - better just to hand code the mess shown at the top?

Any ideas? I'm off now to google "generating php from delphi" - which is probably what I should have done weeks ago :-/

回答1:

You're not just generating PHP. You're generating PHP that in turn generates HTML. Your program will need to be aware of both languages' string-encoding rules. It will probably be easier to write two separate functions for that:

function QuoteStringForPHP(s: string): string;
function QuoteHTMLAttributeValue(s: string): string;

Given your example, you'd use them like this:

ControlName := theControl.Name;
ValueName := ControlName + '_values';
SelectionName := ControlName + '_selection';
Write(thePhpFile, '    echo ' +
  QuoteStringForPHP(
    '<option value=' +
      QuoteHTMLAttributeValue(SelectionName) +
    '>'
  ) +
  '.' +
  '$' + ValueName + '[$_POST[' +
    QuoteStringForPHP(SelectionName) +
  ']];'
);

Writing them is straightforward:

// Input: Any sequence of characters
// Output: A single-quoted PHP string literal
function QuoteStringForPHP(s: string): string;
begin
  // Commented apostrophes are only to fix Stack Overflow's code highlighting
  s := StringReplace(s, '\' {'}, '\\', [rfReplaceAll]);
  s := StringReplace(s, '''', '\''' {'}, [rfReplaceAll]);
  Result := '''' + s + '''';
end;

// Input: Any sequence of valid HTML text characters
// Precondition: s has not already had any HTML encoding applied to
//               it; i.e., no character references
// Output: A single-quoted HTML attribute value
function QuoteHTMLAttributeValue(s: string): string;
begin
  s := StringReplace(s, '&', '&amp;', [rfReplaceAll]);
  s := StringReplace(s, '''', '&apos;', [rfReplaceAll]);
  Result := '''' + s + '''';
end;

I chose to use apostrophes rather than quotation marks since that makes PHP escaping easier. If you use quotation marks for your PHP strings, then you need to worry about variable interpolation. With apostrophes, that problem goes away.

By making QuoteStringForPHP responsible for quoting and escaping, you make escaping easy. There's no more guesswork about which characters need escaping because they all do. The ones that don't need escaping are only added after the escaping work is complete.



回答2:

I've read you question several times, but I can't understand what your problem is. I would leave the code as it is.

But it seems that you don't want to use this tiny, but annoying escape characters in your code? As you described, the escaping algorithm is very error prone. It tries to solve a syntactic problem without semantic informations. But how do you provide the parsing algorithm with this information? Right, use escape characters. But it seems that you don't want to use this tiny, but annoying escape characters in your code? As you described, the escaping algorithm is very error prone. It tries to solve a syntactic problem without semantic informations. But how do you provide the parsing algorithm with this information? Right, use escape characters. But it seems that you don't want to use this tiny, but annoying escape characters in your code? As you described, the escaping algorithm is very error prone. It tries to solve a syntactic problem without semantic informations. But how do you provide the parsing algorithm with this information? Right, use escape characters. ...

;-)



回答3:

Well, I can't know your abilities, so I don't know if you can do it yourself. It is not entirely trivial (since character positions change due to inserting), but I'd say it is a problem for a first programming class. (watch those invariants!)

function escapephp(s: string):string;
var first,n,cur,lastcur : integer;
begin
  result:=s;
  first:=pos('"',result);
  if first>0 then   // first found? 
    begin
      n:=0;     
      cur:=first;
      while cur<>0 do
        begin
          lastcur:=cur;   // keep last found
          cur:=posex('"',result,lastcur+1);  // search next
          if  (lastcur<>first) and (cur<>0) then // next is not last and not first?
            begin
              insert('\"',result,lastcur);  // then insert
              inc(cur,2);                   // we inserted 2 chars so need to correct with 2
            end;
       end;
   end;
end;

The example could do with a bit more thorough testing, I only quickly tested it on your string