Skip to content

Instantly share code, notes, and snippets.

@fredemmott
Created February 21, 2014 23:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fredemmott/9145911 to your computer and use it in GitHub Desktop.
Save fredemmott/9145911 to your computer and use it in GitHub Desktop.
commit 7ef637d6c0fd5d0736dab8a7b7fd2e4eb3730207
Author: Fred Emmott <fredemmott@fb.com>
Date: Fri Feb 21 14:31:31 2014 -0800
Add plumbing for stream metadata; implement for php://
Summary: Match Zend. refs guzzle/guzzle#538
Test Plan: New test
Reviewers: ptarjan
CC: smith, ps, hphp-diffs@lists
Differential Revision: https://phabricator.fb.com/D1185448
Task ID: 3712919
diff --git a/hphp/runtime/base/file.cpp b/hphp/runtime/base/file.cpp
index e8889dd..f35f074 100644
--- a/hphp/runtime/base/file.cpp
+++ b/hphp/runtime/base/file.cpp
@@ -152,10 +152,10 @@ Variant File::Open(const String& filename, const String& mode,
///////////////////////////////////////////////////////////////////////////////
// constructor and destructor
-File::File(bool nonblocking)
+File::File(bool nonblocking, const String& wrapper, const String& stream_type)
: m_isLocal(false), m_fd(-1), m_closed(false), m_nonblocking(nonblocking),
m_writepos(0), m_readpos(0), m_position(0), m_eof(false),
- m_buffer(nullptr) {
+ m_wrapperType(wrapper), m_streamType(stream_type), m_buffer(nullptr) {
}
File::~File() {
@@ -391,7 +391,7 @@ const StaticString
Array File::getMetaData() {
ArrayInit ret(10);
- ret.set(s_wrapper_type, o_getClassName());
+ ret.set(s_wrapper_type, getWrapperType());
ret.set(s_stream_type, getStreamType());
ret.set(s_mode, String(m_mode));
ret.set(s_unread_bytes, 0);
@@ -404,6 +404,13 @@ Array File::getMetaData() {
return ret.create();
}
+String File::getWrapperType() const {
+ if (m_wrapperType.empty()) {
+ return o_getClassName();
+ }
+ return m_wrapperType;
+}
+
///////////////////////////////////////////////////////////////////////////////
// utility functions
diff --git a/hphp/runtime/base/file.h b/hphp/runtime/base/file.h
index 118ded9..b86e4d3 100644
--- a/hphp/runtime/base/file.h
+++ b/hphp/runtime/base/file.h
@@ -66,7 +66,9 @@ public:
public:
static const int USE_INCLUDE_PATH;
- explicit File(bool nonblocking = true);
+ explicit File(bool nonblocking = true,
+ const String& wrapper_type = null_string,
+ const String& stream_type = empty_string);
virtual ~File();
static StaticString& classnameof() {
@@ -126,7 +128,8 @@ public:
virtual Array getMetaData();
virtual Array getWrapperMetaData() { return null_array; }
- virtual const char *getStreamType() const { return "";}
+ String getWrapperType() const;
+ String getStreamType() const { return m_streamType; }
Resource &getStreamContext() { return m_streamContext; }
void setStreamContext(Resource &context) { m_streamContext = context; }
@@ -191,6 +194,8 @@ protected:
std::string m_name;
std::string m_mode;
+ String m_wrapperType;
+ String m_streamType;
Resource m_streamContext;
void closeImpl();
diff --git a/hphp/runtime/base/mem-file.cpp b/hphp/runtime/base/mem-file.cpp
index 98b142d..211bc7c 100644
--- a/hphp/runtime/base/mem-file.cpp
+++ b/hphp/runtime/base/mem-file.cpp
@@ -26,13 +26,16 @@ namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
-MemFile::MemFile()
- : File(false), m_data(nullptr), m_len(-1), m_cursor(0), m_malloced(false) {
+MemFile::MemFile(const String& wrapper, const String& stream)
+ : File(false, wrapper, stream), m_data(nullptr), m_len(-1), m_cursor(0),
+ m_malloced(false) {
m_isLocal = true;
}
-MemFile::MemFile(const char *data, int64_t len)
- : File(false), m_data(nullptr), m_len(len), m_cursor(0), m_malloced(true) {
+MemFile::MemFile(const char *data, int64_t len,
+ const String& wrapper, const String& stream)
+ : File(false, wrapper, stream), m_data(nullptr), m_len(len), m_cursor(0),
+ m_malloced(true) {
m_data = (char*)malloc(len + 1);
if (m_data && len) {
memcpy(m_data, data, len);
diff --git a/hphp/runtime/base/mem-file.h b/hphp/runtime/base/mem-file.h
index 21244b7..d32461d 100644
--- a/hphp/runtime/base/mem-file.h
+++ b/hphp/runtime/base/mem-file.h
@@ -30,8 +30,11 @@ class MemFile : public File {
public:
DECLARE_RESOURCE_ALLOCATION(MemFile);
- MemFile();
- MemFile(const char *data, int64_t len);
+ explicit MemFile(const String& wrapper_type = null_string,
+ const String& stream_type = empty_string);
+ MemFile(const char *data, int64_t len,
+ const String& wrapper_type = null_string,
+ const String& stream_type = empty_string);
virtual ~MemFile();
CLASSNAME_IS("MemFile");
diff --git a/hphp/runtime/base/output-file.cpp b/hphp/runtime/base/output-file.cpp
index 05bf0ce..90ba86b 100644
--- a/hphp/runtime/base/output-file.cpp
+++ b/hphp/runtime/base/output-file.cpp
@@ -25,8 +25,10 @@ namespace HPHP {
// constructor and destructor
const StaticString s_php_output("php://output");
+const StaticString s_php("PHP");
+const StaticString s_output("Output");
-OutputFile::OutputFile(const String& filename) {
+OutputFile::OutputFile(const String& filename): File(true, s_php, s_output) {
if (filename != s_php_output) {
throw FatalErrorException("not a php://output file ");
}
diff --git a/hphp/runtime/base/php-stream-wrapper.cpp b/hphp/runtime/base/php-stream-wrapper.cpp
index 69e4f48..89fad48 100644
--- a/hphp/runtime/base/php-stream-wrapper.cpp
+++ b/hphp/runtime/base/php-stream-wrapper.cpp
@@ -26,6 +26,11 @@
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
+const StaticString s_php("PHP");
+const StaticString s_input("Input");
+const StaticString s_temp("TEMP");
+const StaticString s_memory("MEMORY");
+
File *PhpStreamWrapper::openFD(const char *sFD) {
if (!RuntimeOption::ClientExecutionMode()) {
raise_warning("Direct access to file descriptors "
@@ -47,7 +52,7 @@ File *PhpStreamWrapper::openFD(const char *sFD) {
return nullptr;
}
- return NEWOBJ(PlainFile)(dup(nFD), true);
+ return NEWOBJ(PlainFile)(dup(nFD), true, s_php);
}
@@ -60,21 +65,28 @@ File* PhpStreamWrapper::open(const String& filename, const String& mode,
const char *req = filename.c_str() + sizeof("php://") - 1;
if (!strcasecmp(req, "stdin")) {
- return NEWOBJ(PlainFile)(dup(STDIN_FILENO), true);
+ return NEWOBJ(PlainFile)(dup(STDIN_FILENO), true, s_php);
}
if (!strcasecmp(req, "stdout")) {
- return NEWOBJ(PlainFile)(dup(STDOUT_FILENO), true);
+ return NEWOBJ(PlainFile)(dup(STDOUT_FILENO), true, s_php);
}
if (!strcasecmp(req, "stderr")) {
- return NEWOBJ(PlainFile)(dup(STDERR_FILENO), true);
+ return NEWOBJ(PlainFile)(dup(STDERR_FILENO), true, s_php);
}
if (!strncasecmp(req, "fd/", sizeof("fd/") - 1)) {
return openFD(req + sizeof("fd/") - 1);
}
- if (!strncasecmp(req, "temp", sizeof("temp") - 1) ||
- !strcasecmp(req, "memory")) {
- std::unique_ptr<TempFile> file(NEWOBJ(TempFile)());
+ if (!strncasecmp(req, "temp", sizeof("temp") - 1)) {
+ std::unique_ptr<TempFile> file(NEWOBJ(TempFile)(true, s_php, s_temp));
+ if (!file->valid()) {
+ raise_warning("Unable to create temporary file");
+ return nullptr;
+ }
+ return file.release();
+ }
+ if (!strcasecmp(req, "memory")) {
+ std::unique_ptr<TempFile> file(NEWOBJ(TempFile)(true, s_php, s_memory));
if (!file->valid()) {
raise_warning("Unable to create temporary file");
return nullptr;
@@ -84,7 +96,7 @@ File* PhpStreamWrapper::open(const String& filename, const String& mode,
if (!strcasecmp(req, "input")) {
auto raw_post = g_context->getRawPostData();
- return NEWOBJ(MemFile)(raw_post.c_str(), raw_post.size());
+ return NEWOBJ(MemFile)(raw_post.c_str(), raw_post.size(), s_php, s_input);
}
if (!strcasecmp(req, "output")) {
diff --git a/hphp/runtime/base/plain-file.cpp b/hphp/runtime/base/plain-file.cpp
index 5e118cb..942a639 100644
--- a/hphp/runtime/base/plain-file.cpp
+++ b/hphp/runtime/base/plain-file.cpp
@@ -25,11 +25,18 @@
namespace HPHP {
+const StaticString s_plainfile("plainfile");
+const StaticString s_stdio("STDIO");
+
///////////////////////////////////////////////////////////////////////////////
// constructor and destructor
-PlainFile::PlainFile(FILE *stream, bool nonblocking)
- : File(nonblocking), m_stream(stream), m_buffer(nullptr) {
+PlainFile::PlainFile(FILE *stream, bool nonblocking,
+ const String& wrapper_type, const String& stream_type)
+ : File(nonblocking,
+ wrapper_type.isNull() ? s_plainfile : wrapper_type,
+ stream_type.isNull() ? s_stdio : stream_type),
+ m_stream(stream), m_buffer(nullptr) {
if (stream) {
m_fd = fileno(stream);
m_buffer = (char *)malloc(BUFSIZ);
@@ -39,8 +46,12 @@ PlainFile::PlainFile(FILE *stream, bool nonblocking)
m_isLocal = true;
}
-PlainFile::PlainFile(int fd, bool nonblocking)
- : File(nonblocking), m_stream(nullptr), m_buffer(nullptr) {
+PlainFile::PlainFile(int fd, bool nonblocking,
+ const String& wrapper_type, const String& stream_type)
+ : File(nonblocking,
+ wrapper_type.isNull() ? s_plainfile : wrapper_type,
+ stream_type.isNull() ? s_stdio : stream_type),
+ m_stream(nullptr), m_buffer(nullptr) {
m_fd = fd;
}
diff --git a/hphp/runtime/base/plain-file.h b/hphp/runtime/base/plain-file.h
index 92acf5f..ac312905 100644
--- a/hphp/runtime/base/plain-file.h
+++ b/hphp/runtime/base/plain-file.h
@@ -30,8 +30,14 @@ class PlainFile : public File {
public:
DECLARE_RESOURCE_ALLOCATION(PlainFile);
- explicit PlainFile(FILE *stream = nullptr, bool nonblocking = false);
- explicit PlainFile(int fd, bool nonblocking = false);
+ explicit PlainFile(FILE *stream = nullptr,
+ bool nonblocking = false,
+ const String& wrapper_type = null_string,
+ const String& stream_type = null_string);
+ explicit PlainFile(int fd,
+ bool nonblocking = false,
+ const String& wrapper = null_string,
+ const String& stream_type = null_string);
virtual ~PlainFile();
// overriding ResourceData
@@ -55,7 +61,6 @@ public:
virtual bool stat(struct stat *sb);
FILE *getStream() { return m_stream;}
- virtual const char *getStreamType() const { return "STDIO";}
protected:
FILE *m_stream;
diff --git a/hphp/runtime/base/temp-file.cpp b/hphp/runtime/base/temp-file.cpp
index d0f6d10..a5aa47e 100644
--- a/hphp/runtime/base/temp-file.cpp
+++ b/hphp/runtime/base/temp-file.cpp
@@ -23,7 +23,11 @@ namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
// constructor and destructor
-TempFile::TempFile(bool autoDelete /* = true */) : m_autoDelete(autoDelete) {
+TempFile::TempFile(bool autoDelete /* = true */,
+ const String& wrapper_type,
+ const String& stream_type)
+ : PlainFile(nullptr, false, wrapper_type, stream_type),
+ m_autoDelete(autoDelete) {
char path[PATH_MAX];
// open a temporary file
diff --git a/hphp/runtime/base/temp-file.h b/hphp/runtime/base/temp-file.h
index 7e0d0ad..ca19464 100644
--- a/hphp/runtime/base/temp-file.h
+++ b/hphp/runtime/base/temp-file.h
@@ -30,7 +30,9 @@ class TempFile : public PlainFile {
public:
DECLARE_RESOURCE_ALLOCATION(TempFile);
- explicit TempFile(bool autoDelete = true);
+ explicit TempFile(bool autoDelete = true,
+ const String& wrapper_type = null_string,
+ const String& stream_type = empty_string);
virtual ~TempFile();
// overriding ResourceData
@@ -44,6 +46,8 @@ private:
bool m_autoDelete;
std::string m_rawName;
+ String m_wrapperType;
+
bool closeImpl();
};
diff --git a/hphp/test/slow/streams/php-wrapper-stream-types.php b/hphp/test/slow/streams/php-wrapper-stream-types.php
new file mode 100644
index 0000000..05314be
--- /dev/null
+++ b/hphp/test/slow/streams/php-wrapper-stream-types.php
@@ -0,0 +1,27 @@
+<?php
+
+function main() {
+ $to_open = array(
+ array('php://stdin', 'r'),
+ array('php://stdout', 'w'),
+ array('php://stderr', 'w'),
+ array('php://fd/1', 'w'), // stdout
+ array('php://temp', 'rw+'),
+ array('php://memory', 'rw+'),
+ array('php://input', 'r'),
+ array('php://output', 'w'),
+ );
+ foreach ($to_open as $target) {
+ $stream = call_user_func_array('fopen', $target);
+ $metadata = stream_get_meta_data($stream);
+ var_dump(
+ array(
+ 'target' => $target[0],
+ 'wrapper' => $metadata['wrapper_type'],
+ 'stream' => $metadata['stream_type'],
+ )
+ );
+ }
+}
+
+main();
diff --git a/hphp/test/slow/streams/php-wrapper-stream-types.php.expect b/hphp/test/slow/streams/php-wrapper-stream-types.php.expect
new file mode 100644
index 0000000..7da2ef3
--- /dev/null
+++ b/hphp/test/slow/streams/php-wrapper-stream-types.php.expect
@@ -0,0 +1,64 @@
+array(3) {
+ ["target"]=>
+ string(11) "php://stdin"
+ ["wrapper"]=>
+ string(3) "PHP"
+ ["stream"]=>
+ string(5) "STDIO"
+}
+array(3) {
+ ["target"]=>
+ string(12) "php://stdout"
+ ["wrapper"]=>
+ string(3) "PHP"
+ ["stream"]=>
+ string(5) "STDIO"
+}
+array(3) {
+ ["target"]=>
+ string(12) "php://stderr"
+ ["wrapper"]=>
+ string(3) "PHP"
+ ["stream"]=>
+ string(5) "STDIO"
+}
+array(3) {
+ ["target"]=>
+ string(10) "php://fd/1"
+ ["wrapper"]=>
+ string(3) "PHP"
+ ["stream"]=>
+ string(5) "STDIO"
+}
+array(3) {
+ ["target"]=>
+ string(10) "php://temp"
+ ["wrapper"]=>
+ string(3) "PHP"
+ ["stream"]=>
+ string(4) "TEMP"
+}
+array(3) {
+ ["target"]=>
+ string(12) "php://memory"
+ ["wrapper"]=>
+ string(3) "PHP"
+ ["stream"]=>
+ string(6) "MEMORY"
+}
+array(3) {
+ ["target"]=>
+ string(11) "php://input"
+ ["wrapper"]=>
+ string(3) "PHP"
+ ["stream"]=>
+ string(5) "Input"
+}
+array(3) {
+ ["target"]=>
+ string(12) "php://output"
+ ["wrapper"]=>
+ string(3) "PHP"
+ ["stream"]=>
+ string(6) "Output"
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment