]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-8018 initial import of curl emulation library and handy HTTPRetriever
authorskodak <skodak>
Tue, 2 Jan 2007 20:38:20 +0000 (20:38 +0000)
committerskodak <skodak>
Tue, 2 Jan 2007 20:38:20 +0000 (20:38 +0000)
  http://code.blitzaffe.com/pages/phpclasses/files/libcurl_emulator_52-7
  http://code.blitzaffe.com/pages/phpclasses/files/http_retriever_52-6

lib/libcurlemu/LICENSE [new file with mode: 0644]
lib/libcurlemu/README [new file with mode: 0644]
lib/libcurlemu/class_HTTPRetriever.php [new file with mode: 0755]
lib/libcurlemu/libcurlemu.inc.php [new file with mode: 0755]
lib/libcurlemu/libcurlexternal.inc.php [new file with mode: 0755]
lib/libcurlemu/libcurlnative.inc.php [new file with mode: 0755]
lib/libcurlemu/readme_moodle.txt [new file with mode: 0644]

diff --git a/lib/libcurlemu/LICENSE b/lib/libcurlemu/LICENSE
new file mode 100644 (file)
index 0000000..3912109
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/lib/libcurlemu/README b/lib/libcurlemu/README
new file mode 100644 (file)
index 0000000..de18370
--- /dev/null
@@ -0,0 +1,93 @@
+CURL Extension Emulation Library
+Version 1.0.3
+Copyright 2004-2005, Steve Blinch
+http://code.blitzaffe.com
+============================================================================
+
+DESCRIPTION
+
+Provides a pure-PHP implementation of the PHP CURL extension, for use on
+systems which do not already have the CURL extension installed.  It emulates
+all of the curl_* functions normally provided by the CURL extension itself.
+
+This will automatically detect and use the best CURL implementation available
+on your server.  It will attempt the following, in order:
+
+1) Check for the existence of the "real" CURL PHP Extension.  If it is
+loaded, the library will do nothing (and it will not interfere with the
+"real" extension).
+2) Check for the existence of the CURL console binary (usually located in
+/usr/bin/curl).  If found, the library will emulate the CURL PHP
+extension (including all curl_* functions) and use the console binary
+to execute all requests.
+3) If neither the "real" CURL PHP Extension nor the CURL console binary
+are available, the library will emulate the CURL PHP extension (including
+all curl_* functions) using a native, pure-PHP HTTP client implementation.
+This implementation is somewhat limited, but it provides support for most
+of the common CURL options.  HTTPS (SSL) support is available in this
+mode under PHP 4.3.0 if the OpenSSL Extension is loaded.
+
+Thus, by including this library in your project, you can rely on having some
+level of CURL support regardless of the configuration of the server on which
+it is being used.
+
+
+USAGE
+
+Simply copy all of the libcurlemu files into your project directory, then:
+
+require_once("libcurlemu.inc.php");
+
+After this, you can use all of the curl_* functions documented in the PHP
+Manual.
+
+
+EXAMPLE
+
+// CURL Extension Emulation Library Example
+//
+// Usage should be straightforward; you simply use this script exactly as you
+// would normally use the PHP CURL extension functions.
+
+// first, include libcurlemu.inc.php
+require_once('libcurlemu.inc.php');
+
+// at this point, libcurlemu has detected the best available CURL solution
+// (either the CURL extension, if available, or the CURL commandline binary,
+// if available, or as a last resort, HTTPRetriever, our native-PHP HTTP
+// client implementation) and has implemented the curl_* functions if
+// necessary, so you can use CURL normally and safely assume that all CURL
+// functions are available.
+
+// the rest of this example code is copied straight from the PHP manual's
+// reference for the curl_init() function, and will work fine with libcurlemu
+
+// create a new CURL resource
+$ch = curl_init();
+
+// set URL and other appropriate options
+curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
+curl_setopt($ch, CURLOPT_HEADER, false);
+
+// grab URL and pass it to the browser
+curl_exec($ch);
+
+// close CURL resource, and free up system resources
+curl_close($ch);
+
+
+LICENSE
+
+This script is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This script is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with this script; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
diff --git a/lib/libcurlemu/class_HTTPRetriever.php b/lib/libcurlemu/class_HTTPRetriever.php
new file mode 100755 (executable)
index 0000000..4b52c2a
--- /dev/null
@@ -0,0 +1,1069 @@
+<?php
+/* HTTP Retriever
+ * Version v1.1.9
+ * Copyright 2004-2006, Steve Blinch
+ * http://code.blitzaffe.com
+ * ============================================================================
+ *
+ * DESCRIPTION
+ *
+ * Provides a pure-PHP implementation of an HTTP v1.1 client, including support
+ * for chunked transfer encoding and user agent spoofing.  Both GET and POST
+ * requests are supported.
+ *
+ * This can be used in place of something like CURL or WGET for HTTP requests.
+ * Native SSL (HTTPS) requests are also supported if the OpenSSL extension is 
+ * installed under PHP v4.3.0 or greater.
+ *
+ * If native SSL support is not available, the class will also check for the
+ * CURL extension; if it's installed, it will transparently be used for SSL
+ * (HTTPS) requests.
+ *
+ * If neither native SSL support nor the CURL extension are available, and
+ * libcurlemu (a CURL emulation library available from our web site) is found,
+ * the class will also check for the CURL console binary (usually in 
+ * /usr/bin/curl); if it's installed, it will transparently be used for SSL
+ * requests.
+ *
+ * In short, if it's possible to make an HTTP/HTTPS request from your server,
+ * this class can most likely do it.
+ *
+ *
+ * HISTORY
+ *
+ * 1.1.9 (11-Oct-2006)
+ *             - Added set_transfer_display() and default_transfer_callback()
+ *               methods for transfer progress tracking
+ *             - Suppressed possible "fatal protocol error" when remote SSL server
+ *               closes the connection early
+ *             - Added get_content_type() method
+ *             - make_query_string() now handles arrays
+ *
+ * 1.1.8 (19-Jun-2006)
+ *             - Added set_progress_display() and default_progress_callback()
+ *               methods for debug output
+ *             - Added support for relative URLs in HTTP redirects
+ *             - Added cookie support (sending and receiving)
+ *             - Numerous bug fixes
+ *
+ * 1.1.7 (18-Apr-2006)
+ *             - Added support for automatically following HTTP redirects
+ *             - Added ::get_error() method to get any available error message (be
+ *               it an HTTP result error or an internal/connection error)
+ *             - Added ::cache_hit variable to determine whether the page was cached
+ *
+ * 1.1.6 (04-Mar-2006)
+ *             - Added stream_timeout class variable.
+ *             - Added progress_callback class variable.
+ *             - Added support for braindead servers that ignore Connection: close
+ *
+ *
+ * EXAMPLE
+ *
+ * // HTTPRetriever usage example
+ * require_once("class_HTTPRetriever.php");
+ * $http = &new HTTPRetriever();
+ *
+ *
+ * // Example GET request:
+ * // ----------------------------------------------------------------------------
+ * $keyword = "blitzaffe code"; // search Google for this keyword
+ * if (!$http->get("http://www.google.com/search?hl=en&q=%22".urlencode($keyword)."%22&btnG=Search&meta=")) {
+ *     echo "HTTP request error: #{$http->result_code}: {$http->result_text}";
+ *     return false;
+ * }
+ * echo "HTTP response headers:<br><pre>";
+ * var_dump($http->response_headers);
+ * echo "</pre><br>";
+ * 
+ * echo "Page content:<br><pre>";
+ * echo $http->response;
+ * echo "</pre>";
+ * // ----------------------------------------------------------------------------
+ *  
+ *
+ * // Example POST request:
+ * // ----------------------------------------------------------------------------
+ * $keyword = "blitzaffe code"; // search Google for this keyword
+ * $values = array(
+ *     "hl"=>"en",
+ *     "q"=>"%22".urlencode($keyword)."%22",
+ *     "btnG"=>"Search",
+ *     "meta"=>""
+ * );
+ * // Note: This example is just to demonstrate the POST equivalent of the GET
+ * // example above; running this script will return a 501 Not Implemented, as
+ * // Google does not support POST requests.
+ * if (!$http->post("http://www.google.com/search",$http->make_query_string($values))) {
+ *     echo "HTTP request error: #{$http->result_code}: {$http->result_text}";
+ *     return false;
+ * }
+ * echo "HTTP response headers:<br><pre>";
+ * var_dump($http->response_headers);
+ * echo "</pre><br>";
+ * 
+ * echo "Page content:<br><pre>";
+ * echo $http->response;
+ * echo "</pre>";
+ * // ----------------------------------------------------------------------------
+ *
+ *
+ * LICENSE
+ *
+ * This script is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This script is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *     
+ * You should have received a copy of the GNU General Public License along
+ * with this script; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// define user agent ID's
+define("UA_EXPLORER",0);
+define("UA_MOZILLA",1);
+define("UA_FIREFOX",2);
+define("UA_OPERA",3);
+
+// define progress message severity levels
+define('HRP_DEBUG',0);
+define('HRP_INFO',1);
+define('HRP_ERROR',2);
+
+if (!defined("CURL_PATH")) define("CURL_PATH","/usr/bin/curl");
+
+// if the CURL extension is not loaded, but the CURL Emulation Library is found, try
+// to load it
+if (!extension_loaded("curl") && !defined('HTTPR_NO_REDECLARE_CURL') ) {
+       foreach (array(dirname(__FILE__)."/",dirname(__FILE__)."/libcurlemu/") as $k=>$libcurlemupath) {
+               $libcurlemuinc = $libcurlemupath.'libcurlexternal.inc.php';
+               if (is_readable($libcurlemuinc)) require_once($libcurlemuinc);
+       }
+}
+
+class HTTPRetriever {
+       
+       // Constructor
+       function HTTPRetriever() {
+               // default HTTP headers to send with all requests
+               $this->headers = array(
+                       "Referer"=>"",
+                       "User-Agent"=>"HTTPRetriever/1.0",
+                       "Connection"=>"close"
+               );
+               
+               // HTTP version (has no effect if using CURL)
+               $this->version = "1.1";
+               
+               // Normally, CURL is only used for HTTPS requests; setting this to
+               // TRUE will force CURL for HTTP requests as well.  Not recommended.
+               $this->force_curl = false;
+               
+               // If you don't want to use CURL at all, set this to TRUE.
+               $this->disable_curl = false;
+               
+               // If HTTPS request return an error message about SSL certificates in
+               // $this->error and you don't care about security, set this to TRUE
+               $this->insecure_ssl = false;
+               
+               // Set the maximum time to wait for a connection
+               $this->connect_timeout = 15;
+               
+               // Set the maximum time to allow a transfer to run, or 0 to disable.
+               $this->max_time = 0;
+               
+               // Set the maximum time for a socket read/write operation, or 0 to disable.
+               $this->stream_timeout = 0;
+               
+               // If you're making an HTTPS request to a host whose SSL certificate
+               // doesn't match its domain name, AND YOU FULLY UNDERSTAND THE
+               // SECURITY IMPLICATIONS OF IGNORING THIS PROBLEM, set this to TRUE.
+               $this->ignore_ssl_hostname = false;
+               
+               // If TRUE, the get() and post() methods will close the connection
+               // and return immediately after receiving the HTTP result code
+               $this->result_close = false;
+               
+               // If set to a positive integer value, retrieved pages will be cached
+               // for this number of seconds.  Any subsequent calls within the cache
+               // period will return the cached page, without contacting the remote
+               // server.
+               $this->caching = false;
+               
+               // If $this->caching is enabled, this specifies the folder under which
+               // cached pages are saved.
+               $this->cache_path = '/tmp/';
+               
+               // Set these to perform basic HTTP authentication
+               $this->auth_username = '';
+               $this->auth_password = '';
+               
+               // Optionally set this to a valid callback method to have HTTPRetriever
+               // provide progress messages.  Your callback must accept 2 parameters:
+               // an integer representing the severity (0=debug, 1=information, 2=error),
+               // and a string representing the progress message
+               $this->progress_callback = null;
+               
+               // Optionally set this to a valid callback method to have HTTPRetriever
+               // provide bytes-transferred messages.  Your callbcak must accept 2
+               // parameters: an integer representing the number of bytes transferred,
+               // and an integer representing the total number of bytes expected (or
+               // -1 if unknown).
+               $this->transfer_callback = null;
+               
+               // Set this to TRUE if you HTTPRetriever to transparently follow HTTP
+               // redirects (code 301, 302, 303, and 307).  Optionally set this to a
+               // numeric value to limit the maximum number of redirects to the specified
+               // value.  (Redirection loops are detected automatically.)
+               // Note that non-GET/HEAD requests will NOT be redirected except on code
+               // 303, as per HTTP standards.
+               $this->follow_redirects = false;
+       }
+       
+       // Send an HTTP GET request to $url; if $ipaddress is specified, the
+       // connection will be made to the selected IP instead of resolving the 
+       // hostname in $url.
+       //
+       // If $cookies is set, it should be an array in one of two formats.
+       //
+       // Either: $cookies[ 'cookiename' ] = array (
+       //              '/path/'=>array(
+       //                      'expires'=>time(),
+       //                      'domain'=>'yourdomain.com',
+       //                      'value'=>'cookievalue'
+       //              )
+       // );
+       //
+       // Or, a more simplified format:
+       //      $cookies[ 'cookiename' ] = 'value';
+       //
+       // The former format will automatically check to make sure that the path, domain,
+       // and expiration values match the HTTP request, and will only send the cookie if
+       // they do match.  The latter will force the cookie to be set for the HTTP request
+       // unconditionally.
+       // 
+       function get($url,$ipaddress = false,$cookies = false) {
+               $this->method = "GET";
+               $this->post_data = "";
+               $this->connect_ip = $ipaddress;
+               return $this->_execute_request($url,$cookies);
+       }
+       
+       // Send an HTTP POST request to $url containing the POST data $data.  See ::get()
+       // for a description of the remaining arguments.
+       function post($url,$data="",$ipaddress = false,$cookies = false) {
+               $this->method = "POST";
+               $this->post_data = $data;
+               $this->connect_ip = $ipaddress;
+               return $this->_execute_request($url,$cookies);
+       }
+       
+       // Send an HTTP HEAD request to $url.  See ::get() for a description of the arguments.  
+       function head($url,$ipaddress = false,$cookies = false) {
+               $this->method = "HEAD";
+               $this->post_data = "";
+               $this->connect_ip = $ipaddress;
+               return $this->_execute_request($url,$cookies);
+       }
+               
+       // send an alternate (non-GET/POST) HTTP request to $url
+       function custom($method,$url,$data="",$ipaddress = false,$cookies = false) {
+               $this->method = $method;
+               $this->post_data = $data;
+               $this->connect_ip = $ipaddress;
+               return $this->_execute_request($url,$cookies);
+       }       
+       
+       function array_to_query($arrayname,$arraycontents) {
+               $output = "";
+               foreach ($arraycontents as $key=>$value) {
+                       if (is_array($value)) {
+                               $output .= $this->array_to_query(sprintf('%s[%s]',$arrayname,urlencode($key)),$value);
+                       } else {
+                               $output .= sprintf('%s[%s]=%s&',$arrayname,urlencode($key),urlencode($value));
+                       }
+               }
+               return $output;
+       }
+       
+       // builds a query string from the associative array array $data;
+       // returns a string that can be passed to $this->post()
+       function make_query_string($data) {
+               $output = "";
+               if (is_array($data)) {
+                       foreach ($data as $name=>$value) {
+                               if (is_array($value)) {
+                                       $output .= $this->array_to_query(urlencode($name),$value);
+                               } elseif (is_scalar($value)) {
+                                       $output .= urlencode($name)."=".urlencode($value)."&";
+                               } else {
+                                       $output .= urlencode($name)."=".urlencode(serialize($value)).'&';
+                               }
+                       }
+               }
+               return substr($output,0,strlen($output)-1);
+       }
+
+       
+       // this is pretty limited... but really, if you're going to spoof you UA, you'll probably
+       // want to use a Windows OS for the spoof anyway
+       //
+       // if you want to set the user agent to a custom string, just assign your string to
+       // $this->headers["User-Agent"] directly
+       function set_user_agent($agenttype,$agentversion,$windowsversion) {
+               $useragents = array(
+                       "Mozilla/4.0 (compatible; MSIE %agent%; Windows NT %os%)", // IE
+                       "Mozilla/5.0 (Windows; U; Windows NT %os%; en-US; rv:%agent%) Gecko/20040514", // Moz
+                       "Mozilla/5.0 (Windows; U; Windows NT %os%; en-US; rv:1.7) Gecko/20040803 Firefox/%agent%", // FFox
+                       "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT %os%) Opera %agent%  [en]", // Opera
+               );
+               $agent = $useragents[$agenttype];
+               $this->headers["User-Agent"] = str_replace(array("%agent%","%os%"),array($agentversion,$windowsversion),$agent);
+       }
+       
+       // this isn't presently used as it's now handled inline by the request parser
+       function remove_chunkiness() {
+               $remaining = $this->response;
+               $this->response = "";
+               
+               while ($remaining) {
+                       $hexlen = strpos($remaining,"\r");
+                       $chunksize = substr($remaining,0,$hexlen);
+                       $argstart = strpos($chunksize,';');
+                       if ($argstart!==false) $chunksize = substr($chunksize,0,$argstart);
+                       $chunksize = (int) @hexdec($chunksize);
+
+                       $this->response .= substr($remaining,$hexlen+2,$chunksize);
+                       $remaining = substr($remaining,$hexlen+2+$chunksize+2);
+
+                       if (!$chunksize) {
+                               // either we're done, or something's borked... exit
+                               $this->response .= $remaining;
+                               return;
+                       }
+               }
+       }
+       
+       // (internal) store a page in the cache
+       function _cache_store($token) {
+               $values = array(
+                       "stats"=>$this->stats,
+                       "result_code"=>$this->result_code,
+                       "result_text"=>$this->result_text,
+                       "version"=>$this->version,
+                       "response"=>$this->response,
+                       "response_headers"=>$this->response_headers,
+                       "response_cookies"=>$this->response_cookies,
+                       "raw_response"=>$this->raw_response,
+               );
+               $values = serialize($values);
+
+               $filename = $this->cache_path.$token.'.tmp';
+
+               $fp = @fopen($filename,"w");
+               if (!$fp) {
+                       $this->progress(HRP_DEBUG,"Unable to create cache file");
+                       return false;
+               }
+               fwrite($fp,$values);
+               fclose($fp);
+
+               $this->progress(HRP_DEBUG,"HTTP response stored to cache");
+       }
+       
+       // (internal) fetch a page from the cache
+       function _cache_fetch($token) {
+               $this->cache_hit = false;
+               $this->progress(HRP_DEBUG,"Checking for cached page value");
+
+               $filename = $this->cache_path.$token.'.tmp';
+               if (!file_exists($filename)) {
+                       $this->progress(HRP_DEBUG,"Page not available in cache");
+                       return false;
+               }
+               
+               if (time()-filemtime($filename)>$this->caching) {
+                       $this->progress(HRP_DEBUG,"Page in cache is expired");
+                       @unlink($filename);
+                       return false;
+               }
+               
+               if ($values = file_get_contents($filename)) {
+                       $values = unserialize($values);
+                       if (!$values) {
+                               $this->progress(HRP_DEBUG,"Invalid cache contents");
+                               return false;
+                       }
+                       
+                       $this->stats = $values["stats"];
+                       $this->result_code = $values["result_code"];
+                       $this->result_text = $values["result_text"];
+                       $this->version = $values["version"];
+                       $this->response = $values["response"];
+                       $this->response_headers = $values["response_headers"];
+                       $this->response_cookies = $values["response_cookies"];
+                       $this->raw_response = $values["raw_response"];
+                       
+                       $this->progress(HRP_DEBUG,"Page loaded from cache");
+                       $this->cache_hit = true;
+                       return true;
+               } else {
+                       $this->progress(HRP_DEBUG,"Error reading cache file");
+                       return false;
+               }
+       }
+       
+       function parent_path($path) {
+               if (substr($path,0,1)=='/') $path = substr($path,1);
+               if (substr($path,-1)=='/') $path = substr($path,0,strlen($path)-1);
+               $path = explode('/',$path);
+               array_pop($path);
+               return count($path) ? ('/' . implode('/',$path)) : '';
+       }
+       
+       // $cookies should be an array in one of two formats.
+       //
+       // Either: $cookies[ 'cookiename' ] = array (
+       //              '/path/'=>array(
+       //                      'expires'=>time(),
+       //                      'domain'=>'yourdomain.com',
+       //                      'value'=>'cookievalue'
+       //              )
+       // );
+       //
+       // Or, a more simplified format:
+       //      $cookies[ 'cookiename' ] = 'value';
+       //
+       // The former format will automatically check to make sure that the path, domain,
+       // and expiration values match the HTTP request, and will only send the cookie if
+       // they do match.  The latter will force the cookie to be set for the HTTP request
+       // unconditionally.
+       //      
+       function response_to_request_cookies($cookies,$urlinfo) {
+               
+               // check for simplified cookie format (name=value)
+               $cookiekeys = array_keys($cookies);
+               if (!count($cookiekeys)) return;
+               
+               $testkey = array_pop($cookiekeys);
+               if (!is_array($cookies[ $testkey ])) {
+                       foreach ($cookies as $k=>$v) $this->request_cookies[$k] = $v;
+                       return;
+               }
+               
+               // must not be simplified format, so parse as complex format:
+               foreach ($cookies as $name=>$paths) {
+                       foreach ($paths as $path=>$values) {
+                               // make sure the cookie isn't expired
+                               if ( isset($values['expires']) && ($values['expires']<time()) ) continue;
+                               
+                               $cookiehost = $values['domain'];
+                               $requesthost = $urlinfo['host'];
+                               // make sure the cookie is valid for this host
+                               $domain_match = (
+                                       ($requesthost==$cookiehost) ||
+                                       (substr($requesthost,-(strlen($cookiehost)+1))=='.'.$cookiehost)
+                               );                              
+                               
+                               // make sure the cookie is valid for this path
+                               $cookiepath = $path; if (substr($cookiepath,-1)!='/') $cookiepath .= '/';
+                               $requestpath = $urlinfo['path']; if (substr($requestpath,-1)!='/') $requestpath .= '/';
+                               if (substr($requestpath,0,strlen($cookiepath))!=$cookiepath) continue;
+                               
+                               $this->request_cookies[$name] = $values['value'];
+                       }
+               }
+       }                                       
+       
+       // Execute the request for a particular URL, and transparently follow
+       // HTTP redirects if enabled.  If $cookies is specified, it is assumed
+       // to be an array received from $this->response_cookies and will be
+       // processed to determine which cookies are valid for this host/URL.
+       function _execute_request($url,$cookies = false) {
+               // valid codes for which we transparently follow a redirect
+               $redirect_codes = array(301,302,303,307);
+               // valid methods for which we transparently follow a redirect
+               $redirect_methods = array('GET','HEAD');
+
+               $request_result = false;
+               
+               $this->followed_redirect = false;
+               $this->response_cookies = array();
+
+               $previous_redirects = array();
+               do {
+                       // send the request
+                       $request_result = $this->_send_request($url,$cookies);
+                       $lasturl = $url;
+                       $url = false;
+
+                       // see if a redirect code was received
+                       if ($this->follow_redirects && in_array($this->result_code,$redirect_codes)) {
+                               
+                               // only redirect on a code 303 or if the method was GET/HEAD
+                               if ( ($this->result_code==303) || in_array($this->method,$redirect_methods) ) {
+                                       
+                                       // parse the information from the OLD URL so that we can handle
+                                       // relative links
+                                       $oldurlinfo = parse_url($lasturl);
+                                       
+                                       $url = $this->response_headers['Location'];
+                                       
+                                       // parse the information in the new URL, and fill in any blanks
+                                       // using values from the old URL
+                                       $urlinfo = parse_url($url);
+                                       foreach ($oldurlinfo as $k=>$v) {
+                                               if (!$urlinfo[$k]) $urlinfo[$k] = $v;
+                                       }
+                                       
+                                       // create an absolute path
+                                       if (substr($urlinfo['path'],0,1)!='/') {
+                                               $baseurl = $oldurlinfo['path'];
+                                               if (substr($baseurl,-1)!='/') $baseurl = $this->parent_path($url) . '/';
+                                               $urlinfo['path'] = $baseurl . $urlinfo['path'];
+                                       }
+                                       
+                                       // rebuild the URL
+                                       $url = $this->rebuild_url($urlinfo);
+                                       
+                                       $this->progress(HRP_INFO,'Redirected to '.$url);
+                               }
+                       }
+                       
+                       if ( $url && strlen($url) ) {
+                               
+                               if (isset($previous_redirects[$url])) {
+                                       $this->error = "Infinite redirection loop";
+                                       $request_result = false;
+                                       break;
+                               }
+                               if ( is_numeric($this->follow_redirects) && (count($previous_redirects)>$this->follow_redirects) ) {
+                                       $this->error = "Exceeded redirection limit";
+                                       $request_result = false;
+                                       break;
+                               }
+
+                               $previous_redirects[$url] = true;
+                       }
+
+               } while ($url && strlen($url));
+
+               // clear headers that shouldn't persist across multiple requests
+               $per_request_headers = array('Host','Content-Length');
+               foreach ($per_request_headers as $k=>$v) unset($this->headers[$v]);
+               
+               if (count($previous_redirects)>1) $this->followed_redirect = array_keys($previous_redirects);
+               
+               return $request_result;
+       }
+       
+       // private - sends an HTTP request to $url
+       function _send_request($url,$cookies = false) {
+               $this->progress(HRP_INFO,"Initiating {$this->method} request for $url");
+               if ($this->caching) {
+                       $cachetoken = md5($url.'|'.$this->post_data);
+                       if ($this->_cache_fetch($cachetoken)) return true;
+               }
+               
+               $time_request_start = $this->getmicrotime();
+               
+               $urldata = parse_url($url);
+               $http_host = $urldata['host'] . (isset($urldata['port']) ? ':'.$urldata['port'] : '');
+               
+               if (!isset($urldata["port"]) || !$urldata["port"]) $urldata["port"] = ($urldata["scheme"]=="https") ? 443 : 80;
+               if (!isset($urldata["path"]) || !$urldata["path"]) $urldata["path"] = '/';
+               
+               if (!empty($urldata['user'])) $this->auth_username = $urldata['user'];
+               if (!empty($urldata['pass'])) $this->auth_password = $urldata['pass'];
+               
+               //echo "Sending HTTP/{$this->version} {$this->method} request for ".$urldata["host"].":".$urldata["port"]." page ".$urldata["path"]."<br>";
+               
+               if ($this->version>"1.0") $this->headers["Host"] = $http_host;
+               if ($this->method=="POST") {
+                       $this->headers["Content-Length"] = strlen($this->post_data);
+                       if (!isset($this->headers["Content-Type"])) $this->headers["Content-Type"] = "application/x-www-form-urlencoded";
+               }
+               
+               if ( !empty($this->auth_username) || !empty($this->auth_password) ) {
+                       $this->headers['Authorization'] = 'Basic '.base64_encode($this->auth_username.':'.$this->auth_password);
+               } else {
+                       unset($this->headers['Authorization']);
+               }
+               
+               if (is_array($cookies)) {
+                       $this->response_to_request_cookies($cookies,$urldata);
+               }
+               
+               if (($this->method=="GET") && (!empty($urldata["query"]))) $urldata["path"] .= "?".$urldata["query"];
+               $request = $this->method." ".$urldata["path"]." HTTP/".$this->version."\r\n";
+               $request .= $this->build_headers();
+               $request .= $this->post_data;
+               
+               $this->response = "";
+               
+               // Native SSL support requires the OpenSSL extension, and was introduced in PHP 4.3.0
+               $php_ssl_support = extension_loaded("openssl") && version_compare(phpversion(),"4.3.0")>=0;
+               
+               // if this is a plain HTTP request, or if it's an HTTPS request and OpenSSL support is available,
+               // natively perform the HTTP request
+               if ( ( ($urldata["scheme"]=="http") || ($php_ssl_support && ($urldata["scheme"]=="https")) ) && (!$this->force_curl) ) {
+                       $curl_mode = false;
+
+                       $hostname = $this->connect_ip ? $this->connect_ip : $urldata['host'];
+                       if ($urldata["scheme"]=="https") $hostname = 'ssl://'.$hostname;
+                       
+                       $time_connect_start = $this->getmicrotime();
+
+                       $this->progress(HRP_INFO,'Opening socket connection to '.$hostname.' port '.$urldata['port']);
+
+                       $this->expected_bytes = -1;
+                       $this->received_bytes = 0;
+                       
+                       $fp = @fsockopen ($hostname,$urldata["port"],$errno,$errstr,$this->connect_timeout);
+                       $time_connected = $this->getmicrotime();
+                       $connect_time = $time_connected - $time_connect_start;
+                       if ($fp) {
+                               if ($this->stream_timeout) stream_set_timeout($fp,$this->stream_timeout);
+                               $this->progress(HRP_INFO,"Connected; sending request");
+                               
+                               $this->progress(HRP_DEBUG,$request);
+                               fputs ($fp, $request);
+                               $this->raw_request = $request;
+                               
+                               if ($this->stream_timeout) {
+                                       $meta = socket_get_status($fp);
+                                       if ($meta['timed_out']) {
+                                               $this->error = "Exceeded socket write timeout of ".$this->stream_timeout." seconds";
+                                               $this->progress(HRP_ERROR,$this->error);
+                                               return false;
+                                       }
+                               }
+                               
+                               $this->progress(HRP_INFO,"Request sent; awaiting reply");
+                               
+                               $headers_received = false;
+                               $data_length = false;
+                               $chunked = false;
+                               $iterations = 0;
+                               while (!feof($fp)) {
+               
+                                       if ($data_length>0) {
+                                               $line = fread($fp,$data_length);
+                                               $data_length -= strlen($line);
+                                       } else {
+                                               $line = @fgets($fp,10240);
+                                               if ($chunked) {
+                                                       $line = trim($line);
+                                                       if (!strlen($line)) continue;
+                                                       
+                                                       list($data_length,) = explode(';',$line);
+                                                       $data_length = (int) hexdec(trim($data_length));
+                                                       
+                                                       if ($data_length==0) {
+                                                               $this->progress(HRP_DEBUG,"Done");
+                                                               // end of chunked data
+                                                               break;
+                                                       }
+                                                       $this->progress(HRP_DEBUG,"Chunk length $data_length (0x$line)");
+                                                       continue;
+                                               }
+                                       }
+
+                                       $this->response .= $line;
+                                       
+                                       $iterations++;
+                                       if ($headers_received) {
+                                               if ($time_connected>0) {
+                                                       $time_firstdata = $this->getmicrotime();
+                                                       $process_time = $time_firstdata - $time_connected;
+                                                       $time_connected = 0;
+                                               }
+                                               $this->received_bytes += strlen($line);
+                                               if ($iterations % 20 == 0) {
+                                                       $this->update_transfer_counters();
+                                               }
+                                       }
+
+                                       
+                                       // some dumbass webservers don't respect Connection: close and just
+                                       // leave the connection open, so we have to be diligent about
+                                       // calculating the content length so we can disconnect at the end of
+                                       // the response
+                                       if ( (!$headers_received) && (trim($line)=="") ) {
+                                               $headers_received = true;
+
+                                               if (preg_match('/^Content-Length: ([0-9]+)/im',$this->response,$matches)) {
+                                                       $data_length = (int) $matches[1];
+                                                       $this->progress(HRP_DEBUG,"Content length is $data_length");
+                                                       $this->expected_bytes = $data_length;
+                                                       $this->update_transfer_counters();
+                                               }
+                                               if (preg_match("/^Transfer-Encoding: chunked/im",$this->response,$matches)) {
+                                                       $chunked = true;
+                                                       $this->progress(HRP_DEBUG,"Chunked transfer encoding requested");
+                                               }
+                                               
+                                               if (preg_match_all("/^Set-Cookie: ((.*?)\=(.*?)(?:;\s*(.*))?)$/im",$this->response,$cookielist,PREG_SET_ORDER)) {
+                                                       // get the path for which cookies will be valid if no path is specified
+                                                       $cookiepath = preg_replace('/\/{2,}/','',$urldata['path']);
+                                                       if (substr($cookiepath,-1)!='/') {
+                                                               $cookiepath = explode('/',$cookiepath);
+                                                               array_pop($cookiepath);
+                                                               $cookiepath = implode('/',$cookiepath) . '/';
+                                                       }
+                                                       // process each cookie
+                                                       foreach ($cookielist as $k=>$cookiedata) {
+                                                               list(,$rawcookie,$name,$value,$attributedata) = $cookiedata;
+                                                               $attributedata = explode(';',trim($attributedata));
+                                                               $attributes = array();
+
+                                                               $cookie = array(
+                                                                       'value'=>$value,
+                                                                       'raw'=>trim($rawcookie),
+                                                               );
+                                                               foreach ($attributedata as $k=>$attribute) {
+                                                                       list($attrname,$attrvalue) = explode('=',trim($attribute));
+                                                                       $cookie[$attrname] = $attrvalue;
+                                                               }
+
+                                                               if (!isset($cookie['domain']) || !$cookie['domain']) $cookie['domain'] = $urldata['host'];
+                                                               if (!isset($cookie['path']) || !$cookie['path']) $cookie['path'] = $cookiepath;
+                                                               if (isset($cookie['expires']) && $cookie['expires']) $cookie['expires'] = strtotime($cookie['expires']);
+                                                               
+                                                               if (!$this->validate_response_cookie($cookie,$urldata['host'])) continue;
+                                                               
+                                                               // do not store expired cookies; if one exists, unset it
+                                                               if ( isset($cookie['expires']) && ($cookie['expires']<time()) ) {
+                                                                       unset($this->response_cookies[ $name ][ $cookie['path'] ]);
+                                                                       return false;
+                                                               }
+                                                               
+                                                               $this->response_cookies[ $name ][ $cookie['path'] ] = $cookie;
+                                                       }
+                                               }
+                                       }
+                                       
+                                       //$this->progress(HRP_INFO,"Next [$line]");
+                                       if ($this->stream_timeout) {
+                                               $meta = socket_get_status($fp);
+                                               if ($meta['timed_out']) {
+                                                       $this->error = "Exceeded socket read timeout of ".$this->stream_timeout." seconds";
+                                                       $this->progress(HRP_ERROR,$this->error);
+                                                       return false;
+                                               }
+                                       }
+                                       
+                                       // check time limits if requested
+                                       if ($this->max_time>0) {
+                                               if ($this->getmicrotime() - $time_request_start > $this->max_time) {
+                                                       $this->error = "Exceeded maximum transfer time of ".$this->max_time." seconds";
+                                                       $this->progress(HRP_ERROR,$this->error);
+                                                       return false;
+                                                       break;
+                                               }
+                                       }
+                                       if ($this->result_close) {
+                                               if (preg_match_all("/HTTP\/([0-9\.]+) ([0-9]+) (.*?)[\r\n]/",$this->response,$matches)) {
+                                                       $resultcodes = $matches[2];
+                                                       foreach ($resultcodes as $k=>$code) {
+                                                               if ($code!=100) {
+                                                                       $this->progress(HRP_INFO,'HTTP result code received; closing connection');
+
+                                                                       $this->result_code = $code;
+                                                                       $this->result_text = $matches[3][$k];
+                                                                       fclose($fp);
+                                       
+                                                                       return ($this->result_code==200);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               @fclose ($fp);
+                               
+                               $this->update_transfer_counters();
+                               
+                               if (is_array($this->response_cookies)) {
+                                       // make sure paths are sorted in the order in which they should be applied
+                                       // when setting response cookies
+                                       foreach ($this->response_cookies as $name=>$paths) {
+                                               ksort($this->response_cookies[$name]);
+                                       }
+                               }
+                               $this->progress(HRP_INFO,'Request complete');
+                       } else {
+                               $this->error = strtoupper($urldata["scheme"])." connection to ".$hostname." port ".$urldata["port"]." failed";
+                               $this->progress(HRP_ERROR,$this->error);
+                               return false;
+                       }
+
+               // perform an HTTP/HTTPS request using CURL
+               } elseif ( !$this->disable_curl && ( ($urldata["scheme"]=="https") || ($this->force_curl) ) ) {
+                       $this->progress(HRP_INFO,'Passing HTTP request for $url to CURL');
+                       $curl_mode = true;
+                       if (!$this->_curl_request($url)) return false;
+                       
+               // unknown protocol
+               } else {
+                       $this->error = "Unsupported protocol: ".$urldata["scheme"];
+                       $this->progress(HRP_ERROR,$this->error);
+                       return false;
+               }
+               
+               $this->raw_response = $this->response;
+
+               $totallength = strlen($this->response);
+               
+               do {
+                       $headerlength = strpos($this->response,"\r\n\r\n");
+
+                       $response_headers = explode("\r\n",substr($this->response,0,$headerlength));
+                       $http_status = trim(array_shift($response_headers));
+                       foreach ($response_headers as $line) {
+                               list($k,$v) = explode(":",$line,2);
+                               $this->response_headers[trim($k)] = trim($v);
+                       }
+                       $this->response = substr($this->response,$headerlength+4);
+       
+                       /* // Handled in-transfer now
+                       if (($this->response_headers['Transfer-Encoding']=="chunked") && (!$curl_mode)) {
+                               $this->remove_chunkiness();
+                       }
+                       */
+               
+                       if (!preg_match("/^HTTP\/([0-9\.]+) ([0-9]+) (.*?)$/",$http_status,$matches)) {
+                               $matches = array("",$this->version,0,"HTTP request error");
+                       }
+                       list (,$response_version,$this->result_code,$this->result_text) = $matches;
+
+                       // skip HTTP result code 100 (Continue) responses
+               } while (($this->result_code==100) && ($headerlength));
+               
+               // record some statistics, roughly compatible with CURL's curl_getinfo()
+               if (!$curl_mode) {
+                       $total_time = $this->getmicrotime() - $time_request_start;
+                       $transfer_time = $total_time - $connect_time;
+                       $this->stats = array(
+                               "total_time"=>$total_time,
+                               "connect_time"=>$connect_time,  // time between connection request and connection established
+                               "process_time"=>$process_time,  // time between HTTP request and first data (non-headers) received
+                               "url"=>$url,
+                               "content_type"=>$this->response_headers["Content-Type"],
+                               "http_code"=>$this->result_code,
+                               "header_size"=>$headerlength,
+                               "request_size"=>$totallength,
+                               "filetime"=>strtotime($this->response_headers["Date"]),
+                               "pretransfer_time"=>$connect_time,
+                               "size_download"=>$totallength,
+                               "speed_download"=>$transfer_time > 0 ? round($totallength / $transfer_time) : 0,
+                               "download_content_length"=>$totallength,
+                               "upload_content_length"=>0,
+                               "starttransfer_time"=>$connect_time,
+                       );
+               }
+               
+               
+               $ok = ($this->result_code==200);
+               if ($ok && $this->caching) $this->_cache_store($cachetoken);
+
+               return $ok;
+       }
+       
+       function validate_response_cookie($cookie,$actual_hostname) {
+               // make sure the cookie can't be set for a TLD, eg: '.com'              
+               $cookiehost = $cookie['domain'];
+               $p = strrpos($cookiehost,'.');
+               if ($p===false) return false;
+               
+               $tld = strtolower(substr($cookiehost,$p+1));
+               $special_domains = array("com", "edu", "net", "org", "gov", "mil", "int");
+               $periods_required = in_array($tld,$special_domains) ? 1 : 2;
+               
+               $periods = substr_count($cookiehost,'.');
+               if ($periods<$periods_required) return false;
+               
+               if (substr($actual_hostname,0,1)!='.') $actual_hostname = '.'.$actual_hostname;
+               if (substr($cookiehost,0,1)!='.') $cookiehost = '.'.$cookiehost;
+               $domain_match = (
+                       ($actual_hostname==$cookiehost) ||
+                       (substr($actual_hostname,-strlen($cookiehost))==$cookiehost)
+               );
+               
+               return $domain_match;
+
+       }
+       
+       function build_headers() {
+               $headers = "";
+               foreach ($this->headers as $name=>$value) {
+                       $value = trim($value);
+                       if (empty($value)) continue;
+                       $headers .= "{$name}: {$value}\r\n";
+               }
+
+               if (isset($this->request_cookies) && is_array($this->request_cookies)) {
+                       $cookielist = array();
+                       foreach ($this->request_cookies as $name=>$value) {
+                               $cookielist[] = "{$name}={$value}";
+                       }
+                       if (count($cookielist)) $headers .= "Cookie: ".implode('; ',$cookielist)."\r\n";
+               }
+               
+               
+               $headers .= "\r\n";
+               
+               return $headers;
+       }
+       
+       // opposite of parse_url()
+       function rebuild_url($urlinfo) {
+               $url = $urlinfo['scheme'].'://';
+               
+               if ($urlinfo['user'] || $urlinfo['pass']) {
+                       $url .= $urlinfo['user'];
+                       if ($urlinfo['pass']) {
+                               if ($urlinfo['user']) $url .= ':';
+                               $url .= $urlinfo['pass'];
+                       }
+                       $url .= '@';
+               }
+               
+               $url .= $urlinfo['host'];
+               if ($urlinfo['port']) $url .= ':'.$urlinfo['port'];
+               
+               $url .= $urlinfo['path'];
+               
+               if ($urlinfo['query']) $url .= '?'.$urlinfo['query'];
+               if ($urlinfo['fragment']) $url .= '#'.$urlinfo['fragment'];
+               
+               return $url;
+       }
+       
+       function _replace_hostname(&$url,$new_hostname) {
+               $parts = parse_url($url);
+               $old_hostname = $parts['host'];
+               
+               $parts['host'] = $new_hostname;
+               
+               $url = $this->rebuild_url($parts);
+                               
+               return $old_hostname;
+       }
+       
+       function _curl_request($url) {
+               $this->error = false;
+
+               // if a direct connection IP address was specified,     replace the hostname
+               // in the URL with the IP address, and set the Host: header to the
+               // original hostname
+               if ($this->connect_ip) {
+                       $old_hostname = $this->_replace_hostname($url,$this->connect_ip);
+                       $this->headers["Host"] = $old_hostname;
+               }
+               
+
+               unset($this->headers["Content-Length"]);
+               $headers = explode("\n",$this->build_headers());
+               
+               $ch = curl_init();
+               curl_setopt($ch,CURLOPT_URL, $url); 
+               curl_setopt($ch,CURLOPT_USERAGENT, $this->headers["User-Agent"]); 
+               curl_setopt($ch,CURLOPT_HEADER, 1); 
+               curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); 
+//             curl_setopt($ch,CURLOPT_FOLLOWLOCATION, 1); // native method doesn't support this yet, so it's disabled for consistency
+               curl_setopt($ch,CURLOPT_TIMEOUT, 10);
+               curl_setopt($ch,CURLOPT_HTTPHEADER, $headers);
+               
+               if ($this->method=="POST") {
+                       curl_setopt($ch,CURLOPT_POST,1);
+                       curl_setopt($ch,CURLOPT_POSTFIELDS,$this->post_data);
+               }
+               if ($this->insecure_ssl) {
+                       curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
+               }
+               if ($this->ignore_ssl_hostname) {
+                       curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,1);
+               }
+               
+               $this->response = curl_exec ($ch);
+               if (curl_errno($ch)!=0) {
+                       $this->error = "CURL error #".curl_errno($ch).": ".curl_error($ch);
+               }
+               
+               $this->stats = curl_getinfo($ch);
+               curl_close($ch);
+               
+               return ($this->error === false);
+       }
+       
+       function progress($level,$msg) {
+               if (is_callable($this->progress_callback)) call_user_func($this->progress_callback,$level,$msg);
+       }
+       
+       // Gets any available HTTPRetriever error message (including both internal
+       // errors and HTTP errors)
+       function get_error() {
+               return $this->error ? $this->error : 'HTTP ' . $this->result_code.': '.$this->result_text;
+       }
+       
+       function get_content_type() {
+               if (!$ctype = $this->response_headers['Content-Type']) {
+                       $ctype = $this->response_headers['Content-type'];
+               }
+               list($ctype,) = explode(';',$ctype);
+               
+               return strtolower($ctype);
+       }
+       
+       function update_transfer_counters() {
+               if (is_callable($this->transfer_callback)) call_user_func($this->transfer_callback,$this->received_bytes,$this->expected_bytes);
+       }
+
+       function set_transfer_display($enabled = true) {
+               if ($enabled) {
+                       $this->transfer_callback = array(&$this,'default_transfer_callback');
+               } else {
+                       unset($this->transfer_callback);
+               }
+       }
+       
+       function set_progress_display($enabled = true) {
+               if ($enabled) {
+                       $this->progress_callback = array(&$this,'default_progress_callback');
+               } else {
+                       unset($this->progress_callback);
+               }
+       }
+       
+       function default_progress_callback($severity,$message) {
+               $severities = array(
+                       HRP_DEBUG=>'debug',
+                       HRP_INFO=>'info',
+                       HRP_ERROR=>'error',
+               );
+               
+               echo date('Y-m-d H:i:sa').' ['.$severities[$severity].'] '.$message."\n";
+               flush();
+       }
+
+       function default_transfer_callback($transferred,$expected) {
+               $msg = "Transferred " . round($transferred/1024,1);
+               if ($expected>=0) $msg .= "/" . round($expected/1024,1);
+               $msg .= "KB";
+               if ($expected>0) $msg .= " (".round($transferred*100/$expected,1)."%)";
+               echo date('Y-m-d H:i:sa')." $msg\n";
+               flush();
+       }       
+       
+       function getmicrotime() { 
+               list($usec, $sec) = explode(" ",microtime()); 
+               return ((float)$usec + (float)$sec); 
+       }       
+}
+?>
\ No newline at end of file
diff --git a/lib/libcurlemu/libcurlemu.inc.php b/lib/libcurlemu/libcurlemu.inc.php
new file mode 100755 (executable)
index 0000000..bb04bbc
--- /dev/null
@@ -0,0 +1,105 @@
+<?php
+/* CURL Extension Emulation Library
+ * Version 1.0.3
+ * Copyright 2004-2005, Steve Blinch
+ * http://code.blitzaffe.com
+ * ============================================================================
+ *
+ * DESCRIPTION
+ *
+ * Provides a pure-PHP implementation of the PHP CURL extension, for use on
+ * systems which do not already have the CURL extension installed.  It emulates
+ * all of the curl_* functions normally provided by the CURL extension itself.
+ *
+ * This will automatically detect and use the best CURL implementation available
+ * on your server.  It will attempt the following, in order:
+ *
+ * 1) Check for the existence of the "real" CURL PHP Extension.  If it is
+ *    loaded, the library will do nothing (and it will not interfere with the
+ *    "real" extension).
+ * 2) Check for the existence of the CURL console binary (usually located in
+ *    /usr/bin/curl).  If found, the library will emulate the CURL PHP
+ *    extension (including all curl_* functions) and use the console binary
+ *    to execute all requests.
+ * 3) If neither the "real" CURL PHP Extension nor the CURL console binary
+ *    are available, the library will emulate the CURL PHP extension (including
+ *    all curl_* functions) using a native, pure-PHP HTTP client implementation.
+ *    This implementation is somewhat limited, but it provides support for most
+ *    of the common CURL options.  HTTPS (SSL) support is available in this
+ *    mode under PHP 4.3.0 if the OpenSSL Extension is loaded.
+ *
+ * Thus, by including this library in your project, you can rely on having some
+ * level of CURL support regardless of the configuration of the server on which
+ * it is being used.
+ *
+ *
+ * USAGE
+ *
+ * Simply copy all of the libcurlemu files into your project directory, then:
+ *
+ * require_once("libcurlemu.inc.php");
+ *
+ * After this, you can use all of the curl_* functions documented in the PHP
+ * Manual.
+ *
+ *
+ * EXAMPLE
+ *
+ * // CURL Extension Emulation Library Example
+ * //
+ * // Usage should be straightforward; you simply use this script exactly as you
+ * // would normally use the PHP CURL extension functions.
+ *
+ * // first, include libcurlemu.inc.php
+ * require_once('libcurlemu.inc.php');
+ *
+ * // at this point, libcurlemu has detected the best available CURL solution
+ * // (either the CURL extension, if available, or the CURL commandline binary,
+ * // if available, or as a last resort, HTTPRetriever, our native-PHP HTTP
+ * // client implementation) and has implemented the curl_* functions if
+ * // necessary, so you can use CURL normally and safely assume that all CURL
+ * // functions are available.
+ *
+ * // the rest of this example code is copied straight from the PHP manual's
+ * // reference for the curl_init() function, and will work fine with libcurlemu
+ *
+ * // create a new CURL resource
+ * $ch = curl_init();
+ * 
+ * // set URL and other appropriate options
+ * curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
+ * curl_setopt($ch, CURLOPT_HEADER, false);
+ * 
+ * // grab URL and pass it to the browser
+ * curl_exec($ch);
+ * 
+ * // close CURL resource, and free up system resources
+ * curl_close($ch);
+ *
+ *
+ * LICENSE
+ *
+ * This script is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This script is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *     
+ * You should have received a copy of the GNU General Public License along
+ * with this script; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+if (!extension_loaded('curl') && !function_exists('curl_init')) {
+       define('CURLEXT_MISSING_ABORT',true);
+       require_once(dirname(__FILE__)."/libcurlexternal.inc.php");
+       
+       if (!function_exists('curl_init')) {
+               require_once(dirname(__FILE__)."/class_HTTPRetriever.php");
+               require_once(dirname(__FILE__)."/libcurlnative.inc.php");
+       }
+}
+?>
\ No newline at end of file
diff --git a/lib/libcurlemu/libcurlexternal.inc.php b/lib/libcurlemu/libcurlexternal.inc.php
new file mode 100755 (executable)
index 0000000..f7284f9
--- /dev/null
@@ -0,0 +1,637 @@
+<?php
+/* CURL Extension Emulation Library (Console Binary)
+ * Copyright 2004-2005, Steve Blinch
+ * http://code.blitzaffe.com
+ * ============================================================================
+ *
+ * DESCRIPTION
+ *
+ * Provides a pure-PHP implementation of the PHP CURL extension, for use on
+ * systems which do not already have the CURL extension installed.  It emulates
+ * all of the curl_* functions normally provided by the CURL extension itself
+ * by wrapping the CURL console binary.
+ *
+ * This library will automatically detect whether or not the "real" CURL
+ * extension is installed, and if so, it will not interfere.  Thus, it can be
+ * used to ensure that, one way or another, the CURL functions are available
+ * for use.
+ *
+ * This library is actually a wrapper for the CURL console application (usually
+ * found in /usr/bin/curl), so you must have the CURL binary installed in order
+ * to use this script.
+ *
+ *
+ * USAGE
+ *
+ * Please see the PHP documentation under the "CURL, Client URL Library 
+ * Functions" section for information about using this library.  Almost all of
+ * the documentation and examples in the PHP manual should work with this
+ * library.
+ *
+ *
+ * LICENSE
+ *
+ * This script is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This script is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *     
+ * You should have received a copy of the GNU General Public License along
+ * with this script; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+// if the real CURL PHP extension is installed, exit without doing anything
+if (!extension_loaded("curl")) {
+
+// if the CURL path was not defined by the calling script, define it
+if (!defined("CURL_PATH")) define("CURL_PATH","/usr/bin/curl");
+
+// if the CURL binary was not found, do one of the following:
+//   - if CURLEXT_MISSING_ABORT was defined, then exit without implementing the CURL functions
+//   - if CURLEXT_MISSING_IGNORE was defined, then implement the CURL functions anyway (even
+//     though they won't work without the CURL binary installed)
+//   - otherwise, raise a fatal error and halt the script
+if (!is_executable(CURL_PATH)) {
+       
+       if (defined("CURLEXT_MISSING_ABORT") && CURLEXT_MISSING_ABORT) {
+               return;
+       } elseif (defined("CURLEXT_MISSING_IGNORE") && CURLEXT_MISSING_IGNORE) {
+               // proceed and implement the CURL functions anyway, even though they won't work
+       } else {
+               trigger_error("CURL extension is not loaded, and the commandline version of CURL was not found at ".CURL_PATH,E_USER_ERROR);
+       }
+}
+
+define("CURLEXT_VERSION","1.0.0");
+
+define('CURLOPT_NOTHING',0);
+define('CURLOPT_FILE',10001);
+define('CURLOPT_URL',10002);
+define('CURLOPT_PORT',3);
+define('CURLOPT_PROXY',10004);
+define('CURLOPT_USERPWD',10005);
+define('CURLOPT_PROXYUSERPWD',10006);
+define('CURLOPT_RANGE',10007);
+define('CURLOPT_INFILE',10009);
+define('CURLOPT_ERRORBUFFER',10010);
+define('CURLOPT_WRITEFUNCTION',20011);
+define('CURLOPT_READFUNCTION',20012);
+define('CURLOPT_TIMEOUT',13);
+define('CURLOPT_INFILESIZE',14);
+define('CURLOPT_POSTFIELDS',10015);
+define('CURLOPT_REFERER',10016);
+define('CURLOPT_FTPPORT',10017);
+define('CURLOPT_USERAGENT',10018);
+define('CURLOPT_LOW_SPEED_LIMIT',19);
+define('CURLOPT_LOW_SPEED_TIME',20);
+define('CURLOPT_RESUME_FROM',21);
+define('CURLOPT_COOKIE',10022);
+define('CURLOPT_HTTPHEADER',10023);
+define('CURLOPT_HTTPPOST',10024);
+define('CURLOPT_SSLCERT',10025);
+define('CURLOPT_SSLCERTPASSWD',10026);
+define('CURLOPT_SSLKEYPASSWD',10026);
+define('CURLOPT_CRLF',27);
+define('CURLOPT_QUOTE',10028);
+define('CURLOPT_WRITEHEADER',10029);
+define('CURLOPT_COOKIEFILE',10031);
+define('CURLOPT_SSLVERSION',32);
+define('CURLOPT_TIMECONDITION',33);
+define('CURLOPT_TIMEVALUE',34);
+define('CURLOPT_HTTPREQUEST',10035);
+define('CURLOPT_CUSTOMREQUEST',10036);
+define('CURLOPT_STDERR',10037);
+define('CURLOPT_POSTQUOTE',10039);
+define('CURLOPT_WRITEINFO',10040);
+define('CURLOPT_VERBOSE',41);
+define('CURLOPT_HEADER',42);
+define('CURLOPT_NOPROGRESS',43);
+define('CURLOPT_NOBODY',44);
+define('CURLOPT_FAILONERROR',45);
+define('CURLOPT_UPLOAD',46);
+define('CURLOPT_POST',47);
+define('CURLOPT_FTPLISTONLY',48);
+define('CURLOPT_FTPAPPEND',50);
+define('CURLOPT_NETRC',51);
+define('CURLOPT_FOLLOWLOCATION',52);
+define('CURLOPT_FTPASCII',53);
+define('CURLOPT_TRANSFERTEXT',53);
+define('CURLOPT_PUT',54);
+define('CURLOPT_MUTE',55);
+define('CURLOPT_PROGRESSFUNCTION',20056);
+define('CURLOPT_PROGRESSDATA',10057);
+define('CURLOPT_AUTOREFERER',58);
+define('CURLOPT_PROXYPORT',59);
+define('CURLOPT_POSTFIELDSIZE',60);
+define('CURLOPT_HTTPPROXYTUNNEL',61);
+define('CURLOPT_INTERFACE',10062);
+define('CURLOPT_KRB4LEVEL',10063);
+define('CURLOPT_SSL_VERIFYPEER',64);
+define('CURLOPT_CAINFO',10065);
+define('CURLOPT_PASSWDFUNCTION',20066);
+define('CURLOPT_PASSWDDATA',10067);
+define('CURLOPT_MAXREDIRS',68);
+define('CURLOPT_FILETIME',10069);
+define('CURLOPT_TELNETOPTIONS',10070);
+define('CURLOPT_MAXCONNECTS',71);
+define('CURLOPT_CLOSEPOLICY',72);
+define('CURLOPT_CLOSEFUNCTION',20073);
+define('CURLOPT_FRESH_CONNECT',74);
+define('CURLOPT_FORBID_REUSE',75);
+define('CURLOPT_RANDOM_FILE',10076);
+define('CURLOPT_EGDSOCKET',10077);
+define('CURLOPT_CONNECTTIMEOUT',78);
+define('CURLOPT_HEADERFUNCTION',20079);
+define('CURLOPT_HTTPGET',80);
+define('CURLOPT_SSL_VERIFYHOST',81);
+define('CURLOPT_COOKIEJAR',10082);
+define('CURLOPT_SSL_CIPHER_LIST',10083);
+define('CURLOPT_HTTP_VERSION',84);
+define('CURLOPT_FTP_USE_EPSV',85);
+define('CURLOPT_SSLCERTTYPE',10086);
+define('CURLOPT_SSLKEY',10087);
+define('CURLOPT_SSLKEYTYPE',10088);
+define('CURLOPT_SSLENGINE',10089);
+define('CURLOPT_SSLENGINE_DEFAULT',90);
+define('CURLOPT_DNS_USE_GLOBAL_CACHE',91);
+define('CURLOPT_DNS_CACHE_TIMEOUT',92);
+define('CURLOPT_PREQUOTE',10093); 
+
+define('CURLINFO_EFFECTIVE_URL',1);
+define('CURLINFO_HTTP_CODE',2);
+define('CURLINFO_FILETIME',14);
+define('CURLINFO_TOTAL_TIME',3);
+define('CURLINFO_NAMELOOKUP_TIME',4);
+define('CURLINFO_CONNECT_TIME',5);
+define('CURLINFO_PRETRANSFER_TIME',6);
+define('CURLINFO_STARTTRANSFER_TIME',17);
+define('CURLINFO_REDIRECT_TIME',19);
+define('CURLINFO_REDIRECT_COUNT',20);
+define('CURLINFO_SIZE_UPLOAD',7);
+define('CURLINFO_SIZE_DOWNLOAD',8);
+define('CURLINFO_SPEED_DOWNLOAD',9);
+define('CURLINFO_SPEED_UPLOAD',10);
+define('CURLINFO_HEADER_SIZE',11);
+define('CURLINFO_REQUEST_SIZE',12);
+define('CURLINFO_SSL_VERIFYRESULT',13);
+define('CURLINFO_CONTENT_LENGTH_DOWNLOAD',15);
+define('CURLINFO_CONTENT_LENGTH_UPLOAD',16);
+define('CURLINFO_CONTENT_TYPE',18);
+
+
+define("TIMECOND_ISUNMODSINCE",1);
+define("TIMECOND_IFMODSINCE",2);
+
+
+function _curlopt_name($curlopt) {
+       foreach (get_defined_constants() as $k=>$v) {
+               if ( (substr($k,0,8)=="CURLOPT_") && ($v==$curlopt)) return $k;
+       }
+       return false;
+}
+
+// Initialize a CURL emulation session
+function curl_init($url=false) {
+       $i = $GLOBALS["_CURLEXT_OPT"]["index"]++;
+       $GLOBALS["_CURLEXT_OPT"][$i] = array("url"=>$url);
+       
+       return $i;
+}
+
+// Set an option for a CURL emulation transfer 
+function curl_setopt($ch,$option,$value) {
+       
+       $opt = &$GLOBALS["_CURLEXT_OPT"][$ch];
+       if (!$opt["args"]) $opt["args"] = array();
+       $args = &$opt["args"];
+       if (!$opt["settings"]) $opt["settings"] = array();
+       $settings = &$opt["settings"];
+       
+       switch($option) {
+               case CURLOPT_URL:
+                       $opt["url"] = $value;
+                       break;
+               case CURLOPT_VERBOSE:
+                       $opt["verbose"] = $value>0;
+                       break;
+               case CURLOPT_USERPWD:
+                       if ($value==="") $value = false;
+                       $settings["user"] = $value;
+                       break;
+               case CURLOPT_PROXYUSERPWD:
+                       if ($value==="") $value = false;
+                       $settings["proxy-user"] = $value;
+                       break;
+               case CURLOPT_COOKIE:
+                       if ($value==="") $value = false;
+                       if ( is_bool($value) || (strpos($value,"=")!==false) ) $settings["cookie"] = $value;
+                       break;
+               case CURLOPT_COOKIEFILE:
+                       if ($value==="") $value = false;
+                       $settings["cookie"] = $value;
+                       break;
+               case CURLOPT_COOKIEJAR:
+                       if ($value==="") $value = false;
+                       $settings["cookie-jar"] = $value;
+                       break;
+               case CURLOPT_CUSTOMREQUEST:
+                       if ($value==="") $value = false;
+                       $settings["request"] = $value;
+                       break;
+               case CURLOPT_PROXY:
+                       if ($value==="") $value = false;
+                       $settings["proxy"] = $value;
+                       break;
+               case CURLOPT_INTERFACE:
+                       if ($value==="") $value = false;
+                       $settings["interface"] = $value;
+                       break;
+               case CURLOPT_KRB4LEVEL:
+                       if ($value==="") $value = false;
+                       $settings["krb4"] = $value;
+                       break;
+               case CURLOPT_SSLCERT:
+                       $pass = "";
+                       if (is_string($settings["cert"])) {
+                               list(,$pass) = explode(":",$settings["cert"]);
+                               if (strlen($pass)) $pass = ":$pass";
+                       }
+                       $settings["cert"] = $value.$pass;
+                       break;
+               case CURLOPT_SSLCERTPASSWD:
+                       $filename = "";
+                       if (is_string($settings["cert"])) {
+                               list($filename,) = explode(":",$settings["cert"]);
+                       }
+                       $settings["cert"] = $filename.":".$value;
+                       break;
+               case CURLOPT_RANGE:
+                       if ($value==="") $value = false;
+                       $settings["range"] = $value;
+                       break;
+               case CURLOPT_REFERER:
+                       if ($value==="") $value = false;
+                       $settings["referer"] = $value;
+                       break;
+               case CURLOPT_NOBODY:
+                       $settings["head"] = $value>0;
+                       break;
+               case CURLOPT_FAILONERROR:
+                       $opt["fail_on_error"] = $value>0;
+                       break;
+               case CURLOPT_USERAGENT:
+                       $settings["user-agent"] = $value;
+                       break;
+               case CURLOPT_HEADER:
+                       $settings["include"] = $value>0;
+                       break;
+               case CURLOPT_RETURNTRANSFER:
+                       $opt["return_transfer"] = $value>0;
+                       break;
+               case CURLOPT_TIMEOUT:
+                       $settings["max-time"] = (int) $value;
+                       break;
+               case CURLOPT_HTTPHEADER:
+                       reset($value);
+                       foreach ($value as $k=>$header) $args[] = "header=".$header;
+                       break;
+               case CURLOPT_POST:
+                       $settings["data"]["enabled"] = $value>0;
+                       break;
+               case CURLOPT_POSTFIELDS:
+                       if ($value==="") $value = false;
+                       $settings["data"]["value"] = $value;
+                       break;
+               case CURLOPT_SSL_VERIFYPEER:
+                       $settings["insecure"] = ($value==0);
+                       break;
+               case CURLOPT_SSL_VERIFYHOST:
+                       // not supported by the commandline client
+                       break;
+               case CURLOPT_FOLLOWLOCATION:
+                       $settings["location"] = $value>0;
+                       break;
+               case CURLOPT_PUT:
+                       $settings["upload-file"]["enabled"] = $value>0;
+                       break;
+               case CURLOPT_INFILE:
+                       if ($value==="") $value = false;
+                       
+                       if (is_resource($value)) {
+                               
+                               // Ugh, this is a terrible hack.  The CURL extension accepts a file handle, but
+                               // the CURL binary obviously wants a filename.  Since you can't derive a filename
+                               // from a file handle, we have to make a copy of the file from the file handle,
+                               // then pass the temporary filename to the CURL binary.
+                               
+                               $tmpfilename = tempnam("/tmp","cif");
+                               $fp = @fopen($tmpfilename,"w");
+                               if (!$fp) {
+                                       trigger_error("CURL emulation library could not create a temporary file for CURLOPT_INFILE; upload aborted",E_USER_WARNING);
+                               } else {
+                                       while (!feof($value)) {
+                                               $contents = fread($value,8192);
+                                               fwrite($fp,$contents);
+                                       }
+                                       fclose($fp);
+                                       // if a temporary file was previously created, unlink it
+                                       if ($settings["upload-file"]["value"] && file_exists($settings["upload-file"]["value"])) unlink($settings["upload-file"]["value"]);
+                                       
+                                       // set the new upload-file filename
+                                       $settings["upload-file"]["value"] = $tmpfilename;
+                               }
+                       } else {
+                               trigger_error("CURLOPT_INFILE must specify a valid file resource",E_USER_WARNING);
+                       }
+                       
+                       break;
+               case CURLOPT_MUTE:
+                       // we're already mute, no?
+                       break;
+               case CURLOPT_LOW_SPEED_LIMIT:
+                       $settings["speed-limit"] = (int) $value;
+                       break;
+               case CURLOPT_LOW_SPEED_TIME:
+                       $settings["speed-time"] = (int) $value;
+                       break;
+               case CURLOPT_RESUME_FROM:
+                       $settings["continue-at"] = (int) $value;
+                       break;
+               case CURLOPT_CAINFO:
+                       if ($value==="") $value = false;
+                       $settings["cacert"] = $value;
+                       break;
+               case CURLOPT_SSLVERSION:
+                       $value = (int) $value;
+                       switch($value) {
+                               case 2:
+                               case 3:
+                                       unset($settings["sslv2"]);
+                                       unset($settings["sslv3"]);
+                                       $settings["sslv".$value] = true;
+                                       break;
+                       }
+                       break;
+               case CURLOPT_TIMECONDITION:
+                       // untested - I'm lazy :)
+                       if (!isset($settings["time-cond"]["enabled"])) $settings["time-cond"]["enabled"] = false;
+                       if (!$settings["time-cond"]["value"]) $settings["time-cond"]["value"] = 1;
+
+                       $settings["time-cond"]["value"] = abs($settings["time-cond"]["value"]);
+                       if ($value==TIMECOND_ISUNMODSINCE) {
+                               $settings["time-cond"]["value"] *= -1;
+                       }                       
+                       
+                       break;
+               case CURLOPT_TIMEVALUE:
+                       // untested - I'm lazy :)
+                       if ($settings["time-cond"]["value"]) {
+                               $sign = $settings["time-cond"]["value"] / abs($settings["time-cond"]["value"]);
+                       } else {
+                               $sign = 1;
+                       }
+                       $settings["time-cond"]["value"] = (int) $value * $sign;
+                       break;
+               case CURLOPT_FILE:
+                       if (is_resource($value)) {
+                               $opt["output_handle"] = $value;
+                       } else {
+                               trigger_error("CURLOPT_FILE must specify a valid file resource",E_USER_WARNING);
+                       }
+                       break;
+               case CURLOPT_WRITEHEADER:
+                       if (is_resource($value)) {
+                               $opt["header_handle"] = $value;
+                       } else {
+                               trigger_error("CURLOPT_WRITEHEADER must specify a valid file resource",E_USER_WARNING);
+                       }
+                       break;
+               case CURLOPT_STDERR:
+                       // not implemented for now - not really relevant
+                       break;
+               // FTP stuff not implemented
+               case CURLOPT_QUOTE:
+               case CURLOPT_POSTQUOTE:
+               case CURLOPT_UPLOAD:
+               case CURLOPT_FTPLISTONLY:
+               case CURLOPT_FTPAPPEND:
+               case CURLOPT_FTPPORT:
+               // Other stuff not implemented
+               case CURLOPT_NETRC:
+               default:
+                       trigger_error("CURL emulation does not implement CURL option "._curlopt_name($option),E_USER_WARNING);
+                       break;
+       }
+}
+
+// Perform a CURL emulation session
+function curl_exec($ch) {
+       $opt = &$GLOBALS["_CURLEXT_OPT"][$ch];
+       $url = $opt["url"];
+       $verbose = $opt["verbose"];
+       
+       // ask commandline CURL to return its statistics at the end of its output
+       $opt["settings"]["write-out"] = "%{http_code}|%{time_total}|%{time_namelookup}|%{time_connect}|%{time_pretransfer}|%{time_starttransfer}|%{size_download}|%{size_upload}|%{size_header}|%{size_request}|%{speed_download}|%{speed_upload}|||||||%{content_type}|%{url_effective}";
+       $writeout_order = array(
+               CURLINFO_HTTP_CODE,
+               CURLINFO_TOTAL_TIME,
+               CURLINFO_NAMELOOKUP_TIME,
+               CURLINFO_CONNECT_TIME,
+               CURLINFO_PRETRANSFER_TIME,
+               CURLINFO_STARTTRANSFER_TIME,
+               CURLINFO_SIZE_DOWNLOAD,
+               CURLINFO_SIZE_UPLOAD,
+               CURLINFO_HEADER_SIZE,
+               CURLINFO_REQUEST_SIZE,
+               CURLINFO_SPEED_DOWNLOAD,
+               CURLINFO_SPEED_UPLOAD,
+
+               // the following 5 items are not provided by commandline CURL, and thus are left empty
+               CURLINFO_FILETIME,
+               CURLINFO_REDIRECT_TIME,
+               CURLINFO_SSL_VERIFYRESULT,
+               CURLINFO_CONTENT_LENGTH_DOWNLOAD,
+               CURLINFO_CONTENT_LENGTH_UPLOAD,
+               CURLINFO_REDIRECT_COUNT,
+
+               CURLINFO_CONTENT_TYPE,
+               CURLINFO_EFFECTIVE_URL,
+       );
+
+       // if the CURLOPT_NOBODY option was specified (to remove the body from the output),
+       // but an output file handle was set, we need to tell CURL to return the body so
+       // that we can write it to the output handle and strip it from the output
+       if ($opt["settings"]["head"] && $opt["output_handle"]) {
+               unset($opt["settings"]["head"]);
+               $strip_body = true;
+       }
+       // if the CURLOPT_HEADER option was NOT specified, but a header file handle was
+       // specified, we again need to tell CURL to return the headers so we can write
+       // them, then strip them from the output
+       if (!isset($opt["settings"]["include"]) && isset($opt["header_handle"])) {
+               $opt["settings"]["include"] = true;
+               $strip_headers = true;
+       }
+
+       // build the CURL argument list
+       $arguments = "";
+       foreach ($opt["args"] as $k=>$arg) {
+               list($argname,$argval) = explode('=',$arg,2);
+               $arguments .= "--$argname ".escapeshellarg($argval)." ";
+       }       
+       foreach ($opt["settings"] as $argname=>$argval) {
+               if (is_array($argval)) {
+                       if (isset($argval["enabled"]) && !$argval["enabled"]) continue;
+                       $argval = $argval["value"];
+               }
+               if ($argval===false) continue;
+               if (is_bool($argval)) $argval = "";
+               $arguments .= "--$argname ".escapeshellarg($argval)." ";
+       }
+
+       // build the CURL commandline and execute it
+       $cmd = CURL_PATH." ".$arguments." ".escapeshellarg($url);
+       
+       if ($verbose) echo "libcurlemu: Executing: $cmd\n";
+       exec($cmd,$output,$ret);
+       
+       if ($verbose) {
+               echo "libcurlemu: Result: ";
+               var_dump($output);
+               echo "libcurlemu: Exit code: $ret\n";
+       }
+       
+       // check for errors
+       $opt["errno"] = $ret;
+       if ($ret) $opt["error"] = "CURL error #$ret";
+       
+       // die if CURLOPT_FAILONERROR is set and the HTTP result code is greater than 300
+       if ($opt["fail_on_error"]) {
+               if (preg_match("/^HTTP\/1.[0-9]+ ([0-9]{3}) /",$output[0],$matches)) {
+                       $resultcode = (int) $matches[1];
+                       if ($resultcode>300) die;
+               } else {
+                       die; // couldn't get result code!
+               }
+       }
+       
+       // pull the statistics out from the output
+       $stats = explode('|',array_pop($output));
+       foreach ($writeout_order as $k=>$item) {
+               $opt["stats"][$item] = $stats[$k];
+       }
+
+       // build the response string
+       $output = implode("\r\n",$output);
+
+       
+       // find the header end position if needed
+       if ($strip_headers || $strip_body || isset($opt["header_handle"])) {
+               $headerpos = strpos($output,"\r\n\r\n");
+       }
+
+       // if a file handle was provided for header output, extract the headers
+       // and write them to the handle
+       if (isset($opt["header_handle"])) {
+               $headers = substr($output,0,$headerpos);
+               fwrite($opt["header_handle"],$headers);
+       }
+       
+       // if the caller did not request headers in the output, strip them
+       if ($strip_headers) {
+               $output = substr($output,$headerpos+4);
+       }
+       
+       // if the caller did not request the response body in the output, strip it
+       if ($strip_body) {
+               if ($strip_headers) {
+                       $body = $output;
+                       $output = "";
+               } else {
+                       $body = substr($output,$headerpos+4);
+                       $output = substr($output,0,$headerpos);
+               }
+       }
+       
+       // if a file handle was provided for output, write the output to it
+       if (isset($opt["output_handle"])) {
+               fwrite($opt["output_handle"],$output);
+               
+       // if the caller requested that the response be returned, return it
+       } elseif ($opt["return_transfer"]) {
+               return $output;
+               
+       // otherwise, just echo the output to stdout
+       } else {
+               echo $output;
+       }
+       return true;
+}
+
+function curl_close($ch) {
+       $opt = &$GLOBALS["_CURLEXT_OPT"][$ch];
+       
+       if ($opt["settings"]) {
+               $settings = &$opt["settings"];
+               // if the user used CURLOPT_INFILE to specify a file to upload, remove the
+               // temporary file created for the CURL binary
+               if ($settings["upload-file"]["value"] && file_exists($settings["upload-file"]["value"])) unlink($settings["upload-file"]["value"]);
+       }
+
+       unset($GLOBALS["_CURLEXT_OPT"][$ch]);
+}
+
+function curl_errno($ch) {
+       return (int) $GLOBALS["_CURLEXT_OPT"][$ch]["errno"];
+}
+
+function curl_error($ch) {
+       return $GLOBALS["_CURLEXT_OPT"][$ch]["error"];
+}
+
+function curl_getinfo($ch,$opt=NULL) {
+       if ($opt) {
+               return $GLOBALS["_CURLEXT_OPT"][$ch]["stats"][$opt];
+       } else {
+               $curlinfo_tags = array(
+                       "url"=>CURLINFO_EFFECTIVE_URL,
+                       "content_type"=>CURLINFO_CONTENT_TYPE,
+                       "http_code"=>CURLINFO_HTTP_CODE,
+                       "header_size"=>CURLINFO_HEADER_SIZE,
+                       "request_size"=>CURLINFO_REQUEST_SIZE,
+                       "filetime"=>CURLINFO_FILETIME,
+                       "ssl_verify_result"=>CURLINFO_SSL_VERIFYRESULT,
+                       "redirect_count"=>CURLINFO_REDIRECT_COUNT,
+                       "total_time"=>CURLINFO_TOTAL_TIME,
+                       "namelookup_time"=>CURLINFO_NAMELOOKUP_TIME,
+                       "connect_time"=>CURLINFO_CONNECT_TIME,
+                       "pretransfer_time"=>CURLINFO_PRETRANSFER_TIME,
+                       "size_upload"=>CURLINFO_SIZE_UPLOAD,
+                       "size_download"=>CURLINFO_SIZE_DOWNLOAD,
+                       "speed_download"=>CURLINFO_SPEED_DOWNLOAD,
+                       "speed_upload"=>CURLINFO_SPEED_UPLOAD,
+                       "download_content_length"=>CURLINFO_CONTENT_LENGTH_DOWNLOAD,
+                       "upload_content_length"=>CURLINFO_CONTENT_LENGTH_UPLOAD,
+                       "starttransfer_time"=>CURLINFO_STARTTRANSFER_TIME,
+                       "redirect_time"=>CURLINFO_REDIRECT_TIME
+               );
+               $res = array();
+               foreach ($curlinfo_tags as $tag=>$opt) {
+                       $res[$tag] = $GLOBALS["_CURLEXT_OPT"][$ch]["stats"][$opt];
+               }
+               return $res;
+       }
+}
+
+function curl_version() {
+       return "libcurlemu/".CURLEXT_VERSION."-ext";
+}
+
+}
+?>
\ No newline at end of file
diff --git a/lib/libcurlemu/libcurlnative.inc.php b/lib/libcurlemu/libcurlnative.inc.php
new file mode 100755 (executable)
index 0000000..471a8c0
--- /dev/null
@@ -0,0 +1,453 @@
+<?php
+/* CURL Extension Emulation Library (Native PHP)
+ * Copyright 2004-2005, Steve Blinch
+ * http://code.blitzaffe.com
+ * ============================================================================
+ *
+ * DESCRIPTION
+ *
+ * Provides a pure-PHP implementation of the PHP CURL extension, for use on
+ * systems which do not already have the CURL extension installed.  It emulates
+ * all of the curl_* functions normally provided by the CURL extension itself,
+ * and uses an internal, native-PHP HTTP library to make requests.
+ *
+ * This library will automatically detect whether or not the "real" CURL
+ * extension is installed, and if so, it will not interfere.  Thus, it can be
+ * used to ensure that, one way or another, the CURL functions are available
+ * for use.
+ *
+ * Note that this is only a *rough* emulation of CURL; it is not exact, and
+ * many of CURL's options are not implemented.  For a more precise emulation of
+ * CURL, you may want to try our other libcurlexternal library which is based on
+ * the CURL console binary (and is virtually identical to the CURL extension).
+ *
+ *
+ * USAGE
+ *
+ * Please see the PHP documentation under the "CURL, Client URL Library 
+ * Functions" section for information about using this library.  Almost all of
+ * the documentation and examples in the PHP manual should work with this
+ * library.
+ *
+ *
+ * LICENSE
+ *
+ * This script is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This script is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *     
+ * You should have received a copy of the GNU General Public License along
+ * with this script; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+// if the real CURL PHP extension is installed, exit without doing anything;
+// if libcurlemu is installed and providing a wrapper for the CURL binary,
+// exit without doing anything
+if (!extension_loaded("curl") && !function_exists("curl_init")) {
+
+
+// if the CURL binary was not found, do one of the following:
+//   - if CURLNAT_MISSING_ABORT was defined, then exit without
+//     implementing the CURL functions
+//   - otherwise, raise a fatal error and halt the script
+if (!class_exists("HTTPRetriever")) {
+       if (is_readable(dirname(__FILE__)."/class_HTTPRetriever.php")) {
+               define("HTTPR_NO_REDECLARE_CURL",true);
+               require_once(dirname(__FILE__)."/class_HTTPRetriever.php");
+       } else {
+               if (defined("CURLNAT_MISSING_ABORT") && CURLNAT_MISSING_ABORT) {
+                       return;
+               } else {
+                       trigger_error("CURL extension is not loaded, libcurlemu is not loaded, and the HTTPRetriever class is unavailable",E_USER_ERROR);
+               }
+       }
+}
+
+define("CURLNAT_VERSION","1.0.0");
+
+define('CURLOPT_NOTHING',0);
+define('CURLOPT_FILE',10001);
+define('CURLOPT_URL',10002);
+define('CURLOPT_PORT',3);
+define('CURLOPT_PROXY',10004);
+define('CURLOPT_USERPWD',10005);
+define('CURLOPT_PROXYUSERPWD',10006);
+define('CURLOPT_RANGE',10007);
+define('CURLOPT_INFILE',10009);
+define('CURLOPT_ERRORBUFFER',10010);
+define('CURLOPT_WRITEFUNCTION',20011);
+define('CURLOPT_READFUNCTION',20012);
+define('CURLOPT_TIMEOUT',13);
+define('CURLOPT_INFILESIZE',14);
+define('CURLOPT_POSTFIELDS',10015);
+define('CURLOPT_REFERER',10016);
+define('CURLOPT_FTPPORT',10017);
+define('CURLOPT_USERAGENT',10018);
+define('CURLOPT_LOW_SPEED_LIMIT',19);
+define('CURLOPT_LOW_SPEED_TIME',20);
+define('CURLOPT_RESUME_FROM',21);
+define('CURLOPT_COOKIE',10022);
+define('CURLOPT_HTTPHEADER',10023);
+define('CURLOPT_HTTPPOST',10024);
+define('CURLOPT_SSLCERT',10025);
+define('CURLOPT_SSLCERTPASSWD',10026);
+define('CURLOPT_SSLKEYPASSWD',10026);
+define('CURLOPT_CRLF',27);
+define('CURLOPT_QUOTE',10028);
+define('CURLOPT_WRITEHEADER',10029);
+define('CURLOPT_COOKIEFILE',10031);
+define('CURLOPT_SSLVERSION',32);
+define('CURLOPT_TIMECONDITION',33);
+define('CURLOPT_TIMEVALUE',34);
+define('CURLOPT_HTTPREQUEST',10035);
+define('CURLOPT_CUSTOMREQUEST',10036);
+define('CURLOPT_STDERR',10037);
+define('CURLOPT_POSTQUOTE',10039);
+define('CURLOPT_WRITEINFO',10040);
+define('CURLOPT_VERBOSE',41);
+define('CURLOPT_HEADER',42);
+define('CURLOPT_NOPROGRESS',43);
+define('CURLOPT_NOBODY',44);
+define('CURLOPT_FAILONERROR',45);
+define('CURLOPT_UPLOAD',46);
+define('CURLOPT_POST',47);
+define('CURLOPT_FTPLISTONLY',48);
+define('CURLOPT_FTPAPPEND',50);
+define('CURLOPT_NETRC',51);
+define('CURLOPT_FOLLOWLOCATION',52);
+define('CURLOPT_FTPASCII',53);
+define('CURLOPT_TRANSFERTEXT',53);
+define('CURLOPT_PUT',54);
+define('CURLOPT_MUTE',55);
+define('CURLOPT_PROGRESSFUNCTION',20056);
+define('CURLOPT_PROGRESSDATA',10057);
+define('CURLOPT_AUTOREFERER',58);
+define('CURLOPT_PROXYPORT',59);
+define('CURLOPT_POSTFIELDSIZE',60);
+define('CURLOPT_HTTPPROXYTUNNEL',61);
+define('CURLOPT_INTERFACE',10062);
+define('CURLOPT_KRB4LEVEL',10063);
+define('CURLOPT_SSL_VERIFYPEER',64);
+define('CURLOPT_CAINFO',10065);
+define('CURLOPT_PASSWDFUNCTION',20066);
+define('CURLOPT_PASSWDDATA',10067);
+define('CURLOPT_MAXREDIRS',68);
+define('CURLOPT_FILETIME',10069);
+define('CURLOPT_TELNETOPTIONS',10070);
+define('CURLOPT_MAXCONNECTS',71);
+define('CURLOPT_CLOSEPOLICY',72);
+define('CURLOPT_CLOSEFUNCTION',20073);
+define('CURLOPT_FRESH_CONNECT',74);
+define('CURLOPT_FORBID_REUSE',75);
+define('CURLOPT_RANDOM_FILE',10076);
+define('CURLOPT_EGDSOCKET',10077);
+define('CURLOPT_CONNECTTIMEOUT',78);
+define('CURLOPT_HEADERFUNCTION',20079);
+define('CURLOPT_HTTPGET',80);
+define('CURLOPT_SSL_VERIFYHOST',81);
+define('CURLOPT_COOKIEJAR',10082);
+define('CURLOPT_SSL_CIPHER_LIST',10083);
+define('CURLOPT_HTTP_VERSION',84);
+define('CURLOPT_FTP_USE_EPSV',85);
+define('CURLOPT_SSLCERTTYPE',10086);
+define('CURLOPT_SSLKEY',10087);
+define('CURLOPT_SSLKEYTYPE',10088);
+define('CURLOPT_SSLENGINE',10089);
+define('CURLOPT_SSLENGINE_DEFAULT',90);
+define('CURLOPT_DNS_USE_GLOBAL_CACHE',91);
+define('CURLOPT_DNS_CACHE_TIMEOUT',92);
+define('CURLOPT_PREQUOTE',10093); 
+
+define('CURLINFO_EFFECTIVE_URL',1);
+define('CURLINFO_HTTP_CODE',2);
+define('CURLINFO_FILETIME',14);
+define('CURLINFO_TOTAL_TIME',3);
+define('CURLINFO_NAMELOOKUP_TIME',4);
+define('CURLINFO_CONNECT_TIME',5);
+define('CURLINFO_PRETRANSFER_TIME',6);
+define('CURLINFO_STARTTRANSFER_TIME',17);
+define('CURLINFO_REDIRECT_TIME',19);
+define('CURLINFO_REDIRECT_COUNT',20);
+define('CURLINFO_SIZE_UPLOAD',7);
+define('CURLINFO_SIZE_DOWNLOAD',8);
+define('CURLINFO_SPEED_DOWNLOAD',9);
+define('CURLINFO_SPEED_UPLOAD',10);
+define('CURLINFO_HEADER_SIZE',11);
+define('CURLINFO_REQUEST_SIZE',12);
+define('CURLINFO_SSL_VERIFYRESULT',13);
+define('CURLINFO_CONTENT_LENGTH_DOWNLOAD',15);
+define('CURLINFO_CONTENT_LENGTH_UPLOAD',16);
+define('CURLINFO_CONTENT_TYPE',18);
+
+
+define("TIMECOND_ISUNMODSINCE",1);
+define("TIMECOND_IFMODSINCE",2);
+
+
+function _curlopt_name($curlopt) {
+       foreach (get_defined_constants() as $k=>$v) {
+               if ( (substr($k,0,8)=="CURLOPT_") && ($v==$curlopt)) return $k;
+       }
+       return false;
+}
+
+// Initialize a CURL emulation session
+function curl_init() {
+       $i = $GLOBALS["_CURLNAT_OPT"]["index"]++;
+       $GLOBALS["_CURLNAT_OPT"][$i] = array();
+       $GLOBALS["_CURLNAT_OPT"][$i]["http"] = &new HTTPRetriever();
+       $GLOBALS["_CURLNAT_OPT"][$i]["include_body"] = true;
+       return $i;
+}
+
+// Set an option for a CURL emulation transfer 
+function curl_setopt($ch,$option,$value) {
+       
+       $opt = &$GLOBALS["_CURLNAT_OPT"][$ch];
+       if (!$opt["args"]) $opt["args"] = array();
+       $args = &$opt["args"];
+       if (!$opt["settings"]) $opt["settings"] = array();
+       $settings = &$opt["settings"];
+       $http = &$opt["http"];
+       
+       switch($option) {
+               case CURLOPT_URL:
+                       $opt["url"] = $value;
+                       break;
+               case CURLOPT_CUSTOMREQUEST:
+                       $opt["method"] = $value;
+                       break;
+               case CURLOPT_REFERER:
+                       $http->headers["Referer"] = $value;
+                       break;
+               case CURLOPT_NOBODY:
+                       $opt["include_body"] = $value==0;
+                       break;
+               case CURLOPT_FAILONERROR:
+                       $opt["fail_on_error"] = $value>0;
+                       break;
+               case CURLOPT_USERAGENT:
+                       $http->headers["User-Agent"] = $value;
+                       break;
+               case CURLOPT_HEADER:
+                       $opt["include_headers"] = $value>0;
+                       break;
+               case CURLOPT_RETURNTRANSFER:
+                       $opt["return_transfer"] = $value>0;
+                       break;
+               case CURLOPT_TIMEOUT:
+                       $opt["max-time"] = (int) $value;
+                       break;
+               case CURLOPT_HTTPHEADER:
+                       reset($value);
+                       foreach ($value as $k=>$header) {
+                               list($headername,$headervalue) = explode(":",$header);
+                               $http->headers[$headername] = ltrim($headervalue);
+                       }
+                       break;
+               case CURLOPT_POST:
+                       $opt["post"] = $value>0;
+                       break;
+               case CURLOPT_POSTFIELDS:
+                       $opt["postdata"] = $value;
+                       break;
+               case CURLOPT_MUTE:
+                       // we're already mute, no?
+                       break;
+               case CURLOPT_FILE:
+                       if (is_resource($value)) {
+                               $opt["output_handle"] = $value;
+                       } else {
+                               trigger_error("CURLOPT_FILE must specify a valid file resource",E_USER_WARNING);
+                       }
+                       break;
+               case CURLOPT_WRITEHEADER:
+                       if (is_resource($value)) {
+                               $opt["header_handle"] = $value;
+                       } else {
+                               trigger_error("CURLOPT_WRITEHEADER must specify a valid file resource",E_USER_WARNING);
+                       }
+                       break;
+               case CURLOPT_STDERR:
+                       // not implemented for now - not really relevant
+                       break;
+
+               case CURLOPT_SSL_VERIFYPEER:
+               case CURLOPT_SSL_VERIFYHOST:
+                       // these are automatically disabled using ssl:// anyway
+                       break;
+                       
+               case CURLOPT_USERPWD:
+                       list($curl_user,$curl_pass) = explode(':',$value,2);
+                       $http->auth_username = $curl_user;
+                       $http->auth_password = $curl_pass;
+                       break;
+
+               // Important stuff not implemented (as it's not yet supported by HTTPRetriever)
+               case CURLOPT_PUT:
+               case CURLOPT_INFILE:
+               case CURLOPT_FOLLOWLOCATION:
+               case CURLOPT_PROXYUSERPWD:
+               case CURLOPT_COOKIE:
+               case CURLOPT_COOKIEFILE:
+               case CURLOPT_PROXY:
+               case CURLOPT_RANGE:
+               case CURLOPT_RESUME_FROM:
+
+               // Things that cannot (reasonably) be implemented here
+               case CURLOPT_LOW_SPEED_LIMIT:
+               case CURLOPT_LOW_SPEED_TIME:
+               case CURLOPT_KRB4LEVEL:
+               case CURLOPT_SSLCERT:
+               case CURLOPT_SSLCERTPASSWD:
+               case CURLOPT_SSLVERSION:
+               case CURLOPT_INTERFACE:
+               case CURLOPT_CAINFO:
+               case CURLOPT_TIMECONDITION:
+               case CURLOPT_TIMEVALUE:
+       
+               // FTP stuff not implemented
+               case CURLOPT_QUOTE:
+               case CURLOPT_POSTQUOTE:
+               case CURLOPT_UPLOAD:
+               case CURLOPT_FTPLISTONLY:
+               case CURLOPT_FTPAPPEND:
+               case CURLOPT_FTPPORT:
+               
+               // Other stuff not implemented
+               case CURLOPT_VERBOSE:
+               case CURLOPT_NETRC:
+               default:
+                       trigger_error("CURL emulation does not implement CURL option "._curlopt_name($option),E_USER_WARNING);
+                       break;
+       }
+}
+
+// Perform a CURL emulation session
+function curl_exec($ch) {
+       $opt = &$GLOBALS["_CURLNAT_OPT"][$ch];
+       $url = $opt["url"];
+
+       $http = &$opt["http"];
+       $http->disable_curl = true; // avoid problems with recursion, since we *ARE* CURL
+       
+       // set time limits if requested
+       if ($opt["max-time"]) {
+               $http->connect_timeout = $opt["max-time"];
+               $http->max_time = $opt["max-time"];
+       }
+       
+       if ($opt["post"]) {
+               $res = $http->post($url,$opt["postdata"]);
+       } elseif ($opt["method"]) {
+               $res = $http->custom($opt["method"],$url,$opt["postdata"]);
+       } else {
+               $res = $http->get($url);
+       }
+               
+       // check for errors
+       $opt["errno"] = (!$res && $http->error) ? 1 : 0;
+       if ($opt["errno"]) $opt["error"] = $http->error;
+       
+       // die if CURLOPT_FAILONERROR is set and the HTTP result code is greater than 300
+       if ($opt["fail_on_error"]) {
+               if ($http->result_code>300) die;
+       }
+       
+       $opt["stats"] = $http->stats;
+
+
+       $headers = "";
+       foreach ($http->response_headers as $k=>$v) {
+               $headers .= "$k: $v\r\n";
+       }
+
+       // if a file handle was provided for header output, extract the headers
+       // and write them to the handle
+       if (isset($opt["header_handle"])) {
+               fwrite($opt["header_handle"],$headers);
+       }
+       
+       $output = ($opt["include_headers"] ? $headers."\r\n" : "") . ($opt["include_body"] ? $http->response : "");
+       
+       // if a file handle was provided for output, write the output to it
+       if (isset($opt["output_handle"])) {
+               fwrite($opt["output_handle"],$output);
+               
+       // if the caller requested that the response be returned, return it
+       } elseif ($opt["return_transfer"]) {
+               return $output;
+               
+       // otherwise, just echo the output to stdout
+       } else {
+               echo $output;
+       }
+       return true;
+}
+
+function curl_close($ch) {
+       $opt = &$GLOBALS["_CURLNAT_OPT"][$ch];
+       
+       if ($opt["settings"]) {
+               $settings = &$opt["settings"];
+               // if the user used CURLOPT_INFILE to specify a file to upload, remove the
+               // temporary file created for the CURL binary
+               if ($settings["upload-file"]["value"] && file_exists($settings["upload-file"]["value"])) unlink($settings["upload-file"]["value"]);
+       }
+
+       unset($GLOBALS["_CURLNAT_OPT"][$ch]);
+}
+
+function curl_errno($ch) {
+       return (int) $GLOBALS["_CURLNAT_OPT"][$ch]["errno"];
+}
+
+function curl_error($ch) {
+       return $GLOBALS["_CURLNAT_OPT"][$ch]["error"];
+}
+
+function curl_getinfo($ch,$opt=NULL) {
+       if ($opt) {
+               $curlinfo_tags = array(
+                       CURLINFO_EFFECTIVE_URL=>"url",
+                       CURLINFO_CONTENT_TYPE=>"content_type",
+                       CURLINFO_HTTP_CODE=>"http_code",
+                       CURLINFO_HEADER_SIZE=>"header_size",
+                       CURLINFO_REQUEST_SIZE=>"request_size",
+                       CURLINFO_FILETIME=>"filetime",
+                       CURLINFO_SSL_VERIFYRESULT=>"ssl_verify_result",
+                       CURLINFO_REDIRECT_COUNT=>"redirect_count",
+                       CURLINFO_TOTAL_TIME=>"total_time",
+                       CURLINFO_NAMELOOKUP_TIME=>"namelookup_time",
+                       CURLINFO_CONNECT_TIME=>"connect_time",
+                       CURLINFO_PRETRANSFER_TIME=>"pretransfer_time",
+                       CURLINFO_SIZE_UPLOAD=>"size_upload",
+                       CURLINFO_SIZE_DOWNLOAD=>"size_download",
+                       CURLINFO_SPEED_DOWNLOAD=>"speed_download",
+                       CURLINFO_SPEED_UPLOAD=>"speed_upload",
+                       CURLINFO_CONTENT_LENGTH_DOWNLOAD=>"download_content_length",
+                       CURLINFO_CONTENT_LENGTH_UPLOAD=>"upload_content_length",
+                       CURLINFO_STARTTRANSFER_TIME=>"starttransfer_time",
+                       CURLINFO_REDIRECT_TIME=>"redirect_time"
+               );
+               
+               $key = $curlinfo_tags[$opt];
+               return $GLOBALS["_CURLNAT_OPT"][$ch]["stats"][$key];
+       } else {
+               return $GLOBALS["_CURLNAT_OPT"][$ch]["stats"];
+       }
+}
+
+function curl_version() {
+       return "libcurlemu/".CURLNAT_VERSION."-nat";
+}
+
+}
+?>
\ No newline at end of file
diff --git a/lib/libcurlemu/readme_moodle.txt b/lib/libcurlemu/readme_moodle.txt
new file mode 100644 (file)
index 0000000..046eb2c
--- /dev/null
@@ -0,0 +1,7 @@
+Description of libcurlemu v1.0.3 import into Moodle
+
+Changes:
+ * example.php - removed
+ * original HTTPRetriever v1.1.5 replaced by standalone package v1.1.9
+
+$Id$
\ No newline at end of file