

SSL and PHP Streams, Part 1 - DaveRandom
http://www.docnet.nu/tech-portal/2014/06/26/ssl-and-php-streams-part-1-you-are-doing-it-wrongtm/C0

======
johnnyfaehell
Personally if I was getting data from HTTP in PHP the last thing I would ever
do is use file_get_contents. Just because you can doesn't mean you should.

It's generally advised to set allow_url_include to off which would make this
code not work. Also if you're mention curl in your technical article about
code you should ask yourself why your code isn't using the curl integration in
the language you're using.

Putting a "You are doing it wrong" in your title is just asking for people to
point out everything that is wrong with it.

~~~
TazeTSchnitzel
>Personally if I was getting data from HTTP in PHP the last thing I would ever
do is use file_get_contents. Just because you can doesn't mean you should.

Why not? file_get_contents makes things much simpler, and there's nothing
really wrong with it. Fetching a JSON file is simple, for example:

    
    
      $file = file_get_contents("http://example.com/some.json");
      if ($file === FALSE) {
        die("Failed to get JSON file");
      }
      $data = json_decode($file);
      if ($data === NULL) {
        die("Failed to decode JSON");
      }
      echo htmlspecialchars($data->foo->bar);
    

To be honest, I think cURL is unnecessary in most cases. PHP's HTTP streams do
a better job without relying on an additional extension (HTTP streams are in
the PHP core, while cURL must be built separately and often installed
separately), and the HTTP stream context options with their string key names
are much nicer than the dreaded CURLOPT_* constants.

~~~
johnnyfaehell
Why not?

1) The name of the function is file_get_contents, however you're not getting a
file. It just annoys me, it reads wrong. stream_get_contents is better but I
still wouldn't go reaching for streams for HTTP requests. 2) It provides you
with a lack of control. 3) It's pretty sloppy, to do anything like POST
requests with bodies you have to do hacky stuff.

I wouldn't be writing my own curl call request either I would use a library
such as Guzzle.

~~~
TazeTSchnitzel
>1) The name of the function is file_get_contents, however you're not getting
a file.

No, you are getting a file. It's from a remote location, but it's a file
nonetheless. Are ftp:// resources not files? Are ssh:// resources not files?

>2) It provides you with a lack of control.

Does it? Stream context options give you a degree of control. If
file_get_contents isn't quite right for you, there's also fopen.

>3) It's pretty sloppy, to do anything like POST requests with bodies you have
to do hacky stuff.

    
    
      $ctx = stream_context_create([
        'http' => [
          'method' => 'POST',
          'header' => 'Content-type: application/x-www-form-urlencoded',
          'content' => $some_post_data_here
        ]
      ]);
      $result = file_get_contents('http://example.com/post_endpoint', false, $ctx);
    

Where's the hacky stuff?

It's also shorter and more readable than the equivalent in cURL (the PHP cURL
extension, not the command-line, obviously) and you don't even need to install
an extension!

~~~
johnnyfaehell
> No, you are getting a file. It's from a remote location, but it's a file
> nonetheless. Are ftp:// resources not files? Are ssh:// resources not files?

FTP of course it's a file, it's a FILE TRANSFER PROTOCOL. HTTP is HYPERTEXT
TRANSFER PROTOCOL. You're getting Hypertext. SSH:// are not files. You are
getting the contents of a stream. So you're getting the stream content.

> Does it? Stream context options give you a degree of control. If
> file_get_contents isn't quite right for you, there's also fopen.

To be fair I've not looked into all the options for the streams in http. But
does it give you the option to use global dns cache? How about save the
cookies and reuse them for later requests? Will it deal with gzip for me? If
you can do all the stuff curl can do I'll be all fair enough you've got a
point.

> Where's the hacky stuff?

For me the fact I had to define the header.

> It's also shorter and more readable than the equivalent in cURL

It's not more readable. It says it's getting a file, you lied to me and got
stream contents instead.

> and you don't even need to install an extension!

If you really don't want to install extensions and just use the core language
fair enough, I would rather use the best tools available.

~~~
TazeTSchnitzel
>HTTP is HYPERTEXT TRANSFER PROTOCOL. You're getting Hypertext.

The responses HTTP gives are very file-like. So much so HTTP is often used for
distributing _files_. Indeed, most pages reference several _files_.

> But does it give you the option to use global dns cache?

I don't believe so. I don't think most users need to, however.

> How about save the cookies and reuse them for later requests?

I can't actually remember. Possibly.

> Will it deal with gzip for me?

Yes.

> If you can do all the stuff curl can do I'll be all fair enough you've got a
> point.

It can do _most_ of the stuff cURL does. It doesn't do everything, but my
point is most of the time you don't necessarily need cURL, and IMO this API is
nicer.

> For me the fact I had to define the header.

That's not hacky at all; sending POST requests usually requires specifying a
Content-Type. cURL just automatically does that for you in some cases.

> It's not more readable. It says it's getting a file, you lied to me and got
> stream contents instead.

You did get a file. The file the request returned.

> If you really don't want to install extensions and just use the core
> language fair enough, I would rather use the best tools available.

You might be missing my point.

------
thegeomaster
It by default _doesn 't_ try to verify the certificate of the peer it's
connecting to? Isn't that the whole point of introducing TLS support?

Pardon me if I'm missing something, but that sounds like a horrible design
decision, and anyone who tries to use TLS streams without reading the
documentation is fooled into a false sense of security.

~~~
RobAley
The article is somewhat out of date, the default is now to verify (though you
can turn it off if you need to). A lot is changing with PHP, and people aren't
keeping up.

~~~
johnnyfaehell
I love how this article was written today and is already out of date.

~~~
DaveRandom
I did quite clearly state, this information applies to PHP versions _before_
5.6 (which means that in practice, people need to be doing this for at least
the next two years until 5.6 is widely adopted)...

The next article will cover the changes in 5.6 and why you don't need to set
those ctx opts any more (and a few more you might want to set instead)

------
revelation
Wow, that is terrible. I'm not even talking about the shitty defaults, but
look at the code to make it "secure". String-based programming and all of the
underlying OpenSSL crap just spills up to the API.

No one should be using that, if only because with the _magic strings_
everywhere it is not guaranteed to blow up when there are breaking changes.

~~~
TazeTSchnitzel
>String-based programming

Are we talking about the same language? This is PHP, not Tcl.

>all of the underlying OpenSSL crap just spills up to the API.

None of it does. I mean, there's an extension for OpenSSL, but that's not
what's 'spilling up'. What's happening is there were poor defaults, so people
have to change them. Luckily, PHP 5.6 fixes this.

>No one should be using that, if only because with the magic strings
everywhere it is not guaranteed to blow up when there are breaking changes.

"Magic strings"? Are you seriously trying to compare using string names for
keys to specify options (standard practise in many languages) with magic
numbers?

------
vegancap
Ha no way, I'm sure I had a job interview with these guys. Cool to see some
Manchester based tech on front-page HN.

------
iopq
PHP - Part 1: You Are Doing It Wrong

------
PSeitz
Innovative Titles - You are doing it wrong.

