1

I've got a HTML/PHP code that I pass through a Ruby function. I want it to render a minified PHP rather than just as is. I recon that the shell command php -w would be perfect to do so.

module Haml
  module Filters
    module PHP
      include Base
      ##
      # @param text, string (Haml/PHP code)
      #
      def render(text)

         `php -w <<< "<?php #{text} ?>"`

      end
    end
  end
end

The above code breaks because the HTML/PHP string text contains special characters. What is best way of escaping them?


After posting this question and thanks to comments I did more trial and error.

I established it is caused by only four special characters: " \ $ (backtick) (double quote, backward slash, dollar sign, backtick)

I created a simple solution that works (below).

6
  • 2
    Not entirely clear if this resolves your issue, since you haven't provided a minimal reproducible example... (Can you provide an example of "PHP and HTML code and all sorts of special characters", so anyone reading this question can have some confidence that a proposed solution actually works?), but perhaps Shellwords.escape will suffice? Commented Jan 8, 2020 at 17:38
  • It is difficult to give an example... I run the code on large number of files and kinda not sure what breaks it really... just got to the point that I think it only breaks on escaped double quotes in php code. My Ruby (homebrew) doesn't seem to have shellscape module Commented Jan 8, 2020 at 18:06
  • You may find it convenient to use single quotes when appropriate. The rule for single-quoted strings is that each pair of backslashes is treated as one backslash and a single backslash not followed by a backslash is treated as a single backslash unless it is followed by a single quote, in which case the pair are treated as an escaped quote. Commented Jan 8, 2020 at 21:34
  • 2
    String#gsub has forms that permit you perform the three substitutions you mention with a single gsub. Let str = 'a\b"c$e'. One is to use a block: str.gsub(/[\\"\$]/) { |s| case s; when "\\" then "\\\\\\"; when '"' then "\\\""; else "\\$"; end } #=> "a\\\\\\b\\\"c\\$e". Another is to employ a hash: h = { '\\'=>'\\\\\\', '"'=>'\\"', "$"=>'\\$' } #=> {"\\"=>"\\\\\\", "\""=>"\\\"", "$"=>"\\$"}, then str.gsub(/[\\"\$]/, h) #=> "a\\\\\\b\\\"c\\$e". Commented Jan 8, 2020 at 21:34
  • @Cary Swoveland updated my question, moved to a new solution; escaping from an escaping that is escaped can be pain... If I have a chance to test it I'll improve my solution Commented Jan 9, 2020 at 19:01

3 Answers 3

2

Passing content in on the command line is not just risky, but the wrong way to do it in the first place. Use tools like Open3 to do it by streaming it in directly which avoids the need for escaping altogether.

Feed the input to the STDIN filehandle of your php -w process:

output = ''

Open3.popen2('php', '-w') do |stdin, stdout, wait_thr|
  stdin.write("<?php #{text} ?>")
  stdin.close
  output << stdout.read
end
Sign up to request clarification or add additional context in comments.

1 Comment

Similar advice applies to using backticks or Kernel#system.
0

Have you looked at this answer: Ruby: Escaping special characters in a string

it sounds like that after you've read your file in, you need to strip out the characters.

file = File.open("users.txt")
file_data = file.read
clean_data = file_data.gsub(/\\/, '')

Then print your data to the shell command (You may to do some more escaping)

4 Comments

Yes, saw that answer, doesn't work in with php and shell... but I think I've picked-up the trace of solution, just need to escape few characters really: \, ", $
@Matt If you're writing shell commands you must use shellescape. Don't just half-ass it with this minimal substitution.
Just realising this... :-)
@MaciekRek can you mark this answer as correct if it works with shellescape
0

The below substitution chain seems to work, but as some people pointed out a possible better solution would be using shellescape.

# a breakdown of escaped characters

text.gsub("\\", "\\\\\\")  #   \ backslash (the escape character) 
text.gsub("\"", "\\\"")    #   " double quotation mark
text.gsub("$", "\\$")      #   $ dollar sign
text.gsub("`", "\\\\`")    #   ` backtick

Amended code

module Haml
  module Filters
    module PHP
      include Base
      def render(text)

         text=text.gsub("\\", "\\\\\\").gsub("\"", "\\\"").gsub("$", "\\$").gsub("`", "\\\\`")

         `php -w <<< "<?php #{text} ?>"`

      end
    end
  end
end

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.