pear/Archive_Tar/docs/Archive_Tar.txt000064400000045246150043501310013545 0ustar00Documentation for class Archive_Tar =================================== Last update : 2001-08-15 Overview : ---------- The Archive_Tar class helps in creating and managing GNU TAR format files compressed by GNU ZIP or not. The class offers basic functions like creating an archive, adding files in the archive, extracting files from the archive and listing the archive content. It also provide advanced functions that allow the adding and extraction of files with path manipulation. Sample : -------- // ----- Creating the object (uncompressed archive) $tar_object = new Archive_Tar("tarname.tar"); $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // ----- Creating the archive $v_list[0]="file.txt"; $v_list[1]="data/"; $v_list[2]="file.log"; $tar_object->create($v_list); // ----- Adding files $v_list[0]="dev/file.txt"; $v_list[1]="dev/data/"; $v_list[2]="log/file.log"; $tar_object->add($v_list); // ----- Adding more files $tar_object->add("release/newfile.log release/readme.txt"); // ----- Listing the content if (($v_list = $tar_object->listContent()) != 0) for ($i=0; $i"; echo " .size :'".$v_list[$i][size]."'
"; echo " .mtime :'".$v_list[$i][mtime]."' (".date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")
"; echo " .mode :'".$v_list[$i][mode]."'
"; echo " .uid :'".$v_list[$i][uid]."'
"; echo " .gid :'".$v_list[$i][gid]."'
"; echo " .typeflag :'".$v_list[$i][typeflag]."'
"; } // ----- Extracting the archive in directory "install" $tar_object->extract("install"); Public arguments : ------------------ None Public Methods : ---------------- Method : Archive_Tar($p_tarname, $compress = null) Description : Archive_Tar Class constructor. This flavour of the constructor only declare a new Archive_Tar object, identifying it by the name of the tar file. If the compress argument is set the tar will be read or created as a gzip or bz2 compressed TAR file. Arguments : $p_tarname : A valid filename for the tar archive file. $p_compress : can be null, 'gz' or 'bz2'. For compatibility reason it can also be true. This parameter indicates if gzip or bz2 compression is required. Return value : The Archive_Tar object. Sample : $tar_object = new Archive_Tar("tarname.tar"); $tar_object_compressed = new Archive_Tar("tarname.tgz", true); How it works : Initialize the object. Method : create($p_filelist) Description : This method creates the archive file and add the files / directories that are listed in $p_filelist. If the file already exists and is writable, it is replaced by the new tar. It is a create and not an add. If the file exists and is read-only or is a directory it is not replaced. The method return false and a PEAR error text. The $p_filelist parameter can be an array of string, each string representing a filename or a directory name with their path if needed. It can also be a single string with names separated by a single blank. See also createModify() method for more details. Arguments : $p_filelist : An array of filenames and directory names, or a single string with names separated by a single blank space. Return value : true on success, false on error. Sample 1 : $tar_object = new Archive_Tar("tarname.tar"); $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling $v_list[0]="file.txt"; $v_list[1]="data/"; (Optional '/' at the end) $v_list[2]="file.log"; $tar_object->create($v_list); Sample 2 : $tar_object = new Archive_Tar("tarname.tar"); $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling $tar_object->create("file.txt data/ file.log"); How it works : Just calling the createModify() method with the right parameters. Method : createModify($p_filelist, $p_add_dir, $p_remove_dir = "") Description : This method creates the archive file and add the files / directories that are listed in $p_filelist. If the file already exists and is writable, it is replaced by the new tar. It is a create and not an add. If the file exists and is read-only or is a directory it is not replaced. The method return false and a PEAR error text. The $p_filelist parameter can be an array of string, each string representing a filename or a directory name with their path if needed. It can also be a single string with names separated by a single blank. The path indicated in $p_remove_dir will be removed from the memorized path of each file / directory listed when this path exists. By default nothing is removed (empty path "") The path indicated in $p_add_dir will be added at the beginning of the memorized path of each file / directory listed. However it can be set to empty "". The adding of a path is done after the removing of path. The path add/remove ability enables the user to prepare an archive for extraction in a different path than the origin files are. See also addModify() method for file adding properties. Arguments : $p_filelist : An array of filenames and directory names, or a single string with names separated by a single blank space. $p_add_dir : A string which contains a path to be added to the memorized path of each element in the list. $p_remove_dir : A string which contains a path to be removed from the memorized path of each element in the list, when relevant. Return value : true on success, false on error. Sample 1 : $tar_object = new Archive_Tar("tarname.tar"); $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling $v_list[0]="file.txt"; $v_list[1]="data/"; (Optional '/' at the end) $v_list[2]="file.log"; $tar_object->createModify($v_list, "install"); // files are stored in the archive as : // install/file.txt // install/data // install/data/file1.txt // install/data/... all the files and sub-dirs of data/ // install/file.log Sample 2 : $tar_object = new Archive_Tar("tarname.tar"); $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling $v_list[0]="dev/file.txt"; $v_list[1]="dev/data/"; (Optional '/' at the end) $v_list[2]="log/file.log"; $tar_object->createModify($v_list, "install", "dev"); // files are stored in the archive as : // install/file.txt // install/data // install/data/file1.txt // install/data/... all the files and sub-dirs of data/ // install/log/file.log How it works : Open the file in write mode (erasing the existing one if one), call the _addList() method for adding the files in an empty archive, add the tar footer (512 bytes block), close the tar file. Method : addModify($p_filelist, $p_add_dir, $p_remove_dir="") Description : This method add the files / directories listed in $p_filelist at the end of the existing archive. If the archive does not yet exists it is created. The $p_filelist parameter can be an array of string, each string representing a filename or a directory name with their path if needed. It can also be a single string with names separated by a single blank. The path indicated in $p_remove_dir will be removed from the memorized path of each file / directory listed when this path exists. By default nothing is removed (empty path "") The path indicated in $p_add_dir will be added at the beginning of the memorized path of each file / directory listed. However it can be set to empty "". The adding of a path is done after the removing of path. The path add/remove ability enables the user to prepare an archive for extraction in a different path than the origin files are. If a file/dir is already in the archive it will only be added at the end of the archive. There is no update of the existing archived file/dir. However while extracting the archive, the last file will replace the first one. This results in a none optimization of the archive size. If a file/dir does not exist the file/dir is ignored. However an error text is send to PEAR error. If a file/dir is not readable the file/dir is ignored. However an error text is send to PEAR error. If the resulting filename/dirname (after the add/remove option or not) string is greater than 99 char, the file/dir is ignored. However an error text is send to PEAR error. Arguments : $p_filelist : An array of filenames and directory names, or a single string with names separated by a single blank space. $p_add_dir : A string which contains a path to be added to the memorized path of each element in the list. $p_remove_dir : A string which contains a path to be removed from the memorized path of each element in the list, when relevant. Return value : true on success, false on error. Sample 1 : $tar_object = new Archive_Tar("tarname.tar"); [...] $v_list[0]="dev/file.txt"; $v_list[1]="dev/data/"; (Optional '/' at the end) $v_list[2]="log/file.log"; $tar_object->addModify($v_list, "install"); // files are stored in the archive as : // install/file.txt // install/data // install/data/file1.txt // install/data/... all the files and sub-dirs of data/ // install/file.log Sample 2 : $tar_object = new Archive_Tar("tarname.tar"); [...] $v_list[0]="dev/file.txt"; $v_list[1]="dev/data/"; (Optional '/' at the end) $v_list[2]="log/file.log"; $tar_object->addModify($v_list, "install", "dev"); // files are stored in the archive as : // install/file.txt // install/data // install/data/file1.txt // install/data/... all the files and sub-dirs of data/ // install/log/file.log How it works : If the archive does not exists it create it and add the files. If the archive does exists and is not compressed, it open it, jump before the last empty 512 bytes block (tar footer) and add the files at this point. If the archive does exists and is compressed, a temporary copy file is created. This temporary file is then 'gzip' read block by block until the last empty block. The new files are then added in the compressed file. The adding of files is done by going through the file/dir list, adding files per files, in a recursive way through the directory. Each time a path need to be added/removed it is done before writing the file header in the archive. Method : add($p_filelist) Description : This method add the files / directories listed in $p_filelist at the end of the existing archive. If the archive does not yet exists it is created. The $p_filelist parameter can be an array of string, each string representing a filename or a directory name with their path if needed. It can also be a single string with names separated by a single blank. See addModify() method for details and limitations. Arguments : $p_filelist : An array of filenames and directory names, or a single string with names separated by a single blank space. Return value : true on success, false on error. Sample 1 : $tar_object = new Archive_Tar("tarname.tar"); [...] $v_list[0]="dev/file.txt"; $v_list[1]="dev/data/"; (Optional '/' at the end) $v_list[2]="log/file.log"; $tar_object->add($v_list); Sample 2 : $tar_object = new Archive_Tar("tarname.tgz", true); [...] $v_list[0]="dev/file.txt"; $v_list[1]="dev/data/"; (Optional '/' at the end) $v_list[2]="log/file.log"; $tar_object->add($v_list); How it works : Simply call the addModify() method with the right parameters. Method : addString($p_filename, $p_string, $p_datetime, $p_params) Description : This method add a single string as a file at the end of the existing archive. If the archive does not yet exists it is created. Arguments : $p_filename : A string which contains the full filename path that will be associated with the string. $p_string : The content of the file added in the archive. $p_datetime : (Optional) Timestamp of the file (default = now) $p_params : (Optional) Various file metadata: stamp - As above, timestamp of the file mode - UNIX-style permissions (default 0600) type - Is this a regular file or link (see TAR format spec for how to create a hard/symlink) uid - UNIX-style user ID (default 0 = root) gid - UNIX-style group ID (default 0 = root) Return value : true on success, false on error. Sample 1 : $v_archive = & new Archive_Tar($p_filename); $v_archive->setErrorHandling(PEAR_ERROR_PRINT); $v_result = $v_archive->addString('data/test.txt', 'This is the text of the string'); $v_result = $v_archive->addString( 'data/test.sh', "#!/bin/sh\necho 'Hello'", time(), array( "mode" => 0755, "uid" => 34 ) ); Method : extract($p_path = "") Description : This method extract all the content of the archive in the directory indicated by $p_path.If $p_path is optional, if not set the archive is extracted in the current directory. While extracting a file, if the directory path does not exists it is created. See extractModify() for details and limitations. Arguments : $p_path : Optional path where the files/dir need to by extracted. Return value : true on success, false on error. Sample : $tar_object = new Archive_Tar("tarname.tar"); $tar_object->extract(); How it works : Simply call the extractModify() method with appropriate parameters. Method : extractModify($p_path, $p_remove_path) Description : This method extract all the content of the archive in the directory indicated by $p_path. When relevant the memorized path of the files/dir can be modified by removing the $p_remove_path path at the beginning of the file/dir path. While extracting a file, if the directory path does not exists it is created. While extracting a file, if the file already exists it is replaced without looking for last modification date. While extracting a file, if the file already exists and is write protected, the extraction is aborted. While extracting a file, if a directory with the same name already exists, the extraction is aborted. While extracting a directory, if a file with the same name already exists, the extraction is aborted. While extracting a file/directory if the destination directory exist and is write protected, or does not exist but can not be created, the extraction is aborted. If after extraction an extracted file does not show the correct stored file size, the extraction is aborted. When the extraction is aborted, a PEAR error text is set and false is returned. However the result can be a partial extraction that may need to be manually cleaned. Arguments : $p_path : The path of the directory where the files/dir need to by extracted. $p_remove_path : Part of the memorized path that can be removed if present at the beginning of the file/dir path. Return value : true on success, false on error. Sample : // Imagine tarname.tar with files : // dev/data/file.txt // dev/data/log.txt // readme.txt $tar_object = new Archive_Tar("tarname.tar"); $tar_object->extractModify("install", "dev"); // Files will be extracted there : // install/data/file.txt // install/data/log.txt // install/readme.txt How it works : Open the archive and call a more generic function that can extract only a part of the archive or all the archive. See extractList() method for more details. Method : extractInString($p_filename) Description : This method extract from the archive one file identified by $p_filename. The return value is a string with the file content, or NULL on error. Arguments : $p_filename : The path of the file to extract in a string. Return value : a string with the file content or NULL. Sample : // Imagine tarname.tar with files : // dev/data/file.txt // dev/data/log.txt // dev/readme.txt $v_archive = & new Archive_Tar('tarname.tar'); $v_archive->setErrorHandling(PEAR_ERROR_PRINT); $v_string = $v_archive->extractInString('dev/readme.txt'); echo $v_string; Method : listContent() Description : This method returns an array of arrays that describe each file/directory present in the archive. The array is not sorted, so it show the position of the file in the archive. The file informations are : $file[filename] : Name and path of the file/dir. $file[mode] : File permissions (result of fileperms()) $file[uid] : user id $file[gid] : group id $file[size] : filesize $file[mtime] : Last modification time (result of filemtime()) $file[typeflag] : "" for file, "5" for directory Arguments : Return value : An array of arrays or 0 on error. Sample : $tar_object = new Archive_Tar("tarname.tar"); if (($v_list = $tar_object->listContent()) != 0) for ($i=0; $i"; echo " .size :'".$v_list[$i][size]."'
"; echo " .mtime :'".$v_list[$i][mtime]."' (". date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")
"; echo " .mode :'".$v_list[$i][mode]."'
"; echo " .uid :'".$v_list[$i][uid]."'
"; echo " .gid :'".$v_list[$i][gid]."'
"; echo " .typeflag :'".$v_list[$i][typeflag]."'
"; } How it works : Call the same function as an extract however with a flag to only go through the archive without extracting the files. Method : extractList($p_filelist, $p_path = "", $p_remove_path = "") Description : This method extract from the archive only the files indicated in the $p_filelist. These files are extracted in the current directory or in the directory indicated by the optional $p_path parameter. If indicated the $p_remove_path can be used in the same way as it is used in extractModify() method. Arguments : $p_filelist : An array of filenames and directory names, or a single string with names separated by a single blank space. $p_path : The path of the directory where the files/dir need to by extracted. $p_remove_path : Part of the memorized path that can be removed if present at the beginning of the file/dir path. Return value : true on success, false on error. Sample : // Imagine tarname.tar with files : // dev/data/file.txt // dev/data/log.txt // readme.txt $tar_object = new Archive_Tar("tarname.tar"); $tar_object->extractList("dev/data/file.txt readme.txt", "install", "dev"); // Files will be extracted there : // install/data/file.txt // install/readme.txt How it works : Go through the archive and extract only the files present in the list. pear/PEAR/INSTALL000064400000004170150043501310007245 0ustar00PEAR - The PEAR Installer ========================= Installing the PEAR Installer. You should install PEAR on a local development machine first. Installing PEAR on a remote production machine should only be done after you are familiar with PEAR and have tested code using PEAR on your development machine. There are two methods of installing PEAR - PEAR bundled in PHP - go-pear We will first examine how to install PEAR that is bundled with PHP. Microsoft Windows ================= If you are running PHP 5.2.0 or newer, simply download and run the windows installer (.msi) and PEAR can be automatically installed. Otherwise, for older PHP versions, download the .zip of windows, there is a script included with your PHP distribution that is called "go-pear". You must open a command box in order to run it. Click "start" then click "Run..." and type "cmd.exe" to open a command box. Use "cd" to change directory to the location of PHP where you unzipped it, and run the go-pear command. Unix ==== When compiling PHP from source, you simply need to include the --with-pear directive on the "./configure" command. This is "on" by default in most PHP versions, but it doesn't hurt to list it explicitly. You should also consider enabling the zlib extension via --enable-zlib, so that the PEAR installer will be able to handle gzipped files (i.e. smaller package files for faster downloads). Later, when you run "make install" to install PHP itself, part of the process will be prompts that ask you where you want PEAR to be installed. go-pear ======= For users who cannot perform the above steps, or who wish to obtain the latest PEAR with a slightly higher risk of failure, use go-pear. go-pear is obtained by downloading http://pear.php.net/go-pear and saving it as go-pear.php. After downloading, simply run "php go-pear.php" or open it in a web browser (windows only) to download and install PEAR. You can always ask general installation questions on pear-general@lists.php.net, a public mailing list devoted to support for PEAR packages and installation- related issues. Happy PHPing, we hope PEAR will be a great tool for your development work! pear/PEAR/LICENSE000064400000002705150043501310007223 0ustar00Copyright (c) 1997-2009, Stig Bakken , Gregory Beaver , Helgi Þormar Þorbjörnsson , Tomas V.V.Cox , Martin Jansen . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pear/PEAR/README.rst000064400000004342150043501310007704 0ustar00************************* PEAR - The PEAR Installer ************************* .. image:: https://travis-ci.org/pear/pear-core.svg?branch=stable :target: https://travis-ci.org/pear/pear-core ========================================= What is the PEAR Installer? What is PEAR? ========================================= PEAR is the PHP Extension and Application Repository, found at http://pear.php.net. The **PEAR Installer** is this software, which contains executable files and PHP code that is used to **download and install** PEAR code from pear.php.net. PEAR contains useful **software libraries and applications** such as MDB2 (database abstraction), HTML_QuickForm (HTML forms management), PhpDocumentor (auto-documentation generator), DB_DataObject (Data Access Abstraction), and many hundreds more. Browse all available packages at http://pear.php.net, the list is constantly growing and updating to reflect improvements in the PHP language. .. warning:: Do not run PEAR without installing it - if you downloaded this tarball manually, you MUST install it. Read the instructions in INSTALL prior to use. ============= Documentation ============= Documentation for PEAR can be found at http://pear.php.net/manual/. Installation documentation can be found in the INSTALL file included in this tarball. ===== Tests ===== Run the tests without installation as follows:: $ ./scripts/pear.sh run-tests -r tests You should have the ``Text_Diff`` package installed to get nicer error output. To run the tests with another PHP version, modify ``php_bin`` and set the ``PHP_PEAR_PHP_BIN`` environment variable:: $ pear config-set php_bin /usr/local/bin/php7 $ PHP_PEAR_PHP_BIN=/usr/local/bin/php7 ./scripts/pear.sh run-tests -r tests Happy PHPing, we hope PEAR will be a great tool for your development work! Test dependencies ================= * ``zlib`` ========= Releasing ========= Create a PEAR package, as well as phars for pear-less installation, simply run ``build-release.sh``). ``go-pear.phar`` contains the PEAR installer installer that asks where to install it. It is available from http://pear.php.net/go-pear.phar. ``install-pear-nozlib.phar`` installs PEAR automatically without asking anything. It is shipped with PHP itself. pear/Structures_Graph/LICENSE000064400000016725150043501310012007 0ustar00 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser 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 Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. pear/Structures_Graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg000064400000007714150043501310023271 0ustar00 Structures_Graph Tutorial A first tour of graph datastructure manipulation Introduction Structures_Graph is a package for creating and manipulating graph datastructures. A graph is a set of objects, called nodes, connected by arcs. When used as a datastructure, usually nodes contain data, and arcs represent relationships between nodes. When arcs have a direction, and can be travelled only one way, graphs are said to be directed. When arcs have no direction, and can always be travelled both ways, graphs are said to be non directed. Structures_Graph provides an object oriented API to create and directly query a graph, as well as a set of Manipulator classes to extract information from the graph. Creating a Graph Creating a graph is done using the simple constructor: and passing the constructor a flag telling it whether the graph should be directed. A directed graph will always be directed during its lifetime. It's a permanent characteristic. To fill out the graph, we'll need to create some nodes, and then call Graph::addNode. addNode(&$nodeOne); $directedGraph->addNode(&$nodeTwo); $directedGraph->addNode(&$nodeThree); ]]> and then setup the arcs: connectTo($nodeTwo); $nodeOne->connectTo($nodeThree); ]]> Note that arcs can only be created after the nodes have been inserted into the graph. Associating Data Graphs are only useful as datastructures if they can hold data. Structure_Graph stores data in nodes. Each node contains a setter and a getter for its data. setData("Node One's Data is a String"); $nodeTwo->setData(1976); $nodeThree->setData('Some other string'); print("NodeTwo's Data is an integer: " . $nodeTwo->getData()); ]]> Structure_Graph nodes can also store metadata, alongside with the main data. Metadata differs from regular data just because it is stored under a key, making it possible to store more than one data reference per node. The metadata getter and setter need the key to perform the operation: setMetadata('example key', "Node One's Sample Metadata"); print("Metadata stored under key 'example key' in node one: " . $nodeOne->getMetadata('example key')); $nodeOne->unsetMetadata('example key'); ]]> Querying a Graph Structures_Graph provides for basic querying of the graph: inDegree()); print("NodeOne's outDegree: " . $nodeOne->outDegree()); // and naturally, nodes can report on their arcs $arcs = $nodeOne->getNeighbours(); for ($i=0;$igetData()); } ]]> pear/XML_Util/examples/example.php000064400000021710150043501310013103 0ustar00 * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @category XML * @package XML_Util * @subpackage Examples * @author Stephan Schmidt * @copyright 2003-2008 Stephan Schmidt * @license http://opensource.org/licenses/bsd-license New BSD License * @version CVS: $Id$ * @link http://pear.php.net/package/XML_Util */ /** * set error level */ error_reporting(E_ALL); require_once 'XML/Util.php'; /** * replacing XML entities */ print 'replace XML entities:
'; print XML_Util::replaceEntities('This string contains < & >.'); print "\n

\n"; /** * reversing XML entities */ print 'replace XML entities:
'; print XML_Util::reverseEntities('This string contains < & >.'); print "\n

\n"; /** * building XML declaration */ print 'building XML declaration:
'; print htmlspecialchars(XML_Util::getXMLDeclaration()); print "\n

\n"; print 'building XML declaration with additional attributes:
'; print htmlspecialchars(XML_Util::getXMLDeclaration('1.0', 'UTF-8', true)); print "\n

\n"; /** * building document type declaration */ print 'building DocType declaration:
'; print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', 'http://pear.php.net/dtd/package-1.0')); print "\n

\n"; print 'building DocType declaration with public ID (does not exist):
'; print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', array('uri' => 'http://pear.php.net/dtd/package-1.0', 'id' => '-//PHP//PEAR/DTD PACKAGE 0.1'))); print "\n

\n"; print 'building DocType declaration with internal DTD:
'; print '
';
    print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', 
        'http://pear.php.net/dtd/package-1.0', 
        ''));
    print '
'; print "\n

\n"; /** * creating an attribute string */ $att = array( 'foo' => 'bar', 'argh' => 'tomato' ); print 'converting array to string:
'; print XML_Util::attributesToString($att); print "\n

\n"; /** * creating an attribute string with linebreaks */ $att = array( 'foo' => 'bar', 'argh' => 'tomato' ); print 'converting array to string (including line breaks):
'; print '
';
    print XML_Util::attributesToString($att, true, true);
    print '
'; print "\n

\n"; /** * splitting a qualified tag name */ print 'splitting qualified tag name:
'; print '
';
    print_r(XML_Util::splitQualifiedName('xslt:stylesheet'));
    print '
'; print "\n
\n"; /** * splitting a qualified tag name (no namespace) */ print 'splitting qualified tag name (no namespace):
'; print '
';
    print_r(XML_Util::splitQualifiedName('foo'));
    print '
'; print "\n
\n"; /** * splitting a qualified tag name (no namespace, but default namespace specified) */ print 'splitting qualified tag name ' . '(no namespace, but default namespace specified):
'; print '
';
    print_r(XML_Util::splitQualifiedName('foo', 'bar'));
    print '
'; print "\n
\n"; /** * verifying XML names */ print 'verifying \'My private tag\':
'; print '
';
    print_r(XML_Util::isValidname('My Private Tag'));
    print '
'; print "\n

\n"; print 'verifying \'-MyTag\':
'; print '
';
    print_r(XML_Util::isValidname('-MyTag'));
    print '
'; print "\n

\n"; /** * creating an XML tag */ $tag = array( 'namespace' => 'foo', 'localPart' => 'bar', 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), 'content' => 'I\'m inside the tag' ); print 'creating a tag with namespace and local part:
'; print htmlentities(XML_Util::createTagFromArray($tag)); print "\n

\n"; /** * creating an XML tag */ $tag = array( 'qname' => 'foo:bar', 'namespaceUri' => 'http://foo.com', 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), 'content' => 'I\'m inside the tag' ); print 'creating a tag with qualified name and namespaceUri:
'; print htmlentities(XML_Util::createTagFromArray($tag)); print "\n

\n"; /** * creating an XML tag */ $tag = array( 'qname' => 'bar', 'namespaceUri' => 'http://foo.com', 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable') ); print 'creating an empty tag without namespace but namespace Uri:
'; print htmlentities(XML_Util::createTagFromArray($tag)); print "\n

\n"; /** * creating an XML tag with more namespaces */ $tag = array( 'namespace' => 'foo', 'localPart' => 'bar', 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), 'content' => 'I\'m inside the tag', 'namespaces' => array( 'bar' => 'http://bar.com', 'pear' => 'http://pear.php.net', ) ); print 'creating an XML tag with more namespaces:
'; print htmlentities(XML_Util::createTagFromArray($tag)); print "\n

\n"; /** * creating an XML tag with a CData Section */ $tag = array( 'qname' => 'foo', 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), 'content' => 'I\'m inside the tag' ); print 'creating a tag with CData section:
'; print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_CDATA_SECTION)); print "\n

\n"; /** * creating an XML tag with a CData Section */ $tag = array( 'qname' => 'foo', 'attributes' => array('key' => 'value', 'argh' => 'tütü'), 'content' => 'Also XHTML-tags can be created ' . 'and HTML entities can be replaced Ä ä Ü ö <>.' ); print 'creating a tag with HTML entities:
'; print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_ENTITIES_HTML)); print "\n

\n"; /** * creating an XML tag with createTag */ print 'creating a tag with createTag:
'; print htmlentities(XML_Util::createTag('myNs:myTag', array('foo' => 'bar'), 'This is inside the tag', 'http://www.w3c.org/myNs#')); print "\n

\n"; /** * trying to create an XML tag with an array as content */ $tag = array( 'qname' => 'bar', 'content' => array('foo' => 'bar') ); print 'trying to create an XML tag with an array as content:
'; print '
';
    print_r(XML_Util::createTagFromArray($tag));
    print '
'; print "\n

\n"; /** * trying to create an XML tag without a name */ $tag = array( 'attributes' => array('foo' => 'bar'), ); print 'trying to create an XML tag without a name:
'; print '
';
    print_r(XML_Util::createTagFromArray($tag));
    print '
'; print "\n

\n"; ?> pear/XML_Util/examples/example2.php000064400000011353150043501310013167 0ustar00 * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @category XML * @package XML_Util * @subpackage Examples * @author Stephan Schmidt * @copyright 2003-2008 Stephan Schmidt * @license http://opensource.org/licenses/bsd-license New BSD License * @version CVS: $Id$ * @link http://pear.php.net/package/XML_Util */ /** * set error level */ error_reporting(E_ALL); require_once 'XML/Util.php'; /** * creating a start element */ print 'creating a start element:
'; print htmlentities(XML_Util::createStartElement('myNs:myTag', array('foo' => 'bar'), 'http://www.w3c.org/myNs#')); print "\n

\n"; /** * creating a start element */ print 'creating a start element:
'; print htmlentities(XML_Util::createStartElement('myTag', array(), 'http://www.w3c.org/myNs#')); print "\n

\n"; /** * creating a start element */ print 'creating a start element:
'; print '
';
    print htmlentities(XML_Util::createStartElement('myTag', 
        array('foo' => 'bar', 'argh' => 'tomato'), 
        'http://www.w3c.org/myNs#', true));
    print '
'; print "\n

\n"; /** * creating an end element */ print 'creating an end element:
'; print htmlentities(XML_Util::createEndElement('myNs:myTag')); print "\n

\n"; /** * creating a CData section */ print 'creating a CData section:
'; print htmlentities(XML_Util::createCDataSection('I am content.')); print "\n

\n"; /** * creating a comment */ print 'creating a comment:
'; print htmlentities(XML_Util::createComment('I am a comment.')); print "\n

\n"; /** * creating an XML tag with multiline mode */ $tag = array( 'qname' => 'foo:bar', 'namespaceUri' => 'http://foo.com', 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), 'content' => 'I\'m inside the tag & contain dangerous chars' ); print 'creating a tag with qualified name and namespaceUri:
'; print '
';
    print htmlentities(XML_Util::createTagFromArray($tag, 
        XML_UTIL_REPLACE_ENTITIES, true));
    print '
'; print "\n

\n"; /** * create an attribute string without replacing the entities */ $atts = array('series' => 'Starsky & Hutch', 'channel' => 'ABC'); print 'creating a attribute string, ' . 'entities in values already had been replaced:
'; print htmlentities(XML_Util::attributesToString($atts, true, false, false, false, XML_UTIL_ENTITIES_NONE)); print "\n

\n"; /** * using the array-syntax for attributesToString() */ $atts = array('series' => 'Starsky & Hutch', 'channel' => 'ABC'); print 'using the array-syntax for attributesToString()
'; print htmlentities(XML_Util::attributesToString($atts, array('entities' => XML_UTIL_ENTITIES_NONE))); print "\n

\n"; ?> alt-php80-snuffleupagus/CONTRIBUTING.md000064400000013046150043501310013373 0ustar00## Contributing First off, thank you for considering contributing to snuffleupagus. ### 1. Where do I go from here? If you've noticed a bug or have a question, look at the [faq](https://snuffleupagus.readthedocs.io/faq.html) and [search the issue tracker](https://github.com/jvoisin/snuffleupagus/issues) to see if someone else has already created a ticket. If not, go ahead and [make one](https://github.com/jvoisin/snuffleupagus/issues/new)! ### 2. Fork & create a branch If this is something you think you can fix, then [fork snuffleupagus](https://help.github.com/articles/fork-a-repo) and create a branch with a descriptive name. A good branch name would be (where issue #325 is the ticket you're working on): ```sh git checkout -b 325-kill-sql-injections ``` ### 3. Get the test suite running Just type `make coverage` or `make debug`, the testsuite should be run automatically. Please add tests if you're fixing a bug or adding a new feature: we do have a [high coverage](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master) (functions, lines and branches), and intend to keep it that way. #### 3.3 Debugging failures in the test suite If your changes have introduced run-time failures in the test-suite, you can easily troubleshoot them by inspecting the files that [php has generated](https://qa.php.net/write-test.php#analyzing-failing-tests) for this purpose. A nice trick is to edit the `.sh` file to prepend `gdb --args` to it before launching it, in order to run the failing test inside GDB. ### 4. Did you find a bug? * **Ensure the bug was not already reported** by [searching all issues](https://github.com/jvoisin/snuffleupagus/issues?q=). * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/jvoisin/snuffleupagus/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. ### 5. Get the style right Your patch should follow the same conventions & pass the same code quality checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to ensure a consistent code-style. Please run it with `clang-format --style="{BasedOnStyle: google, SortIncludes: false}"` before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format). ### 6. Make a Pull Request At this point, you should switch back to your master branch and make sure it's up to date with our upstream master branch: ```sh git remote add upstream git@github.com:jvoisin/snuffleupagus.git git checkout master git pull upstream master ``` Then update your feature branch from your local copy of master, and push it! ```sh git checkout 325-kill-sql-injections git rebase master git push --set-upstream origin 325-kill-sql-injections ``` Finally, go to GitHub and [make a Pull Request](https://help.github.com/articles/creating-a-pull-request) :D Travis CI will [run our test suite](https://travis-ci.org/jvoisin/snuffleupagus) against all supported PHP versions. We care about quality, so your PR won't be merged until all tests pass. It's unlikely, but it's possible that your changes pass tests in one PHP version but fail in another. In that case, you'll have to setup your development environment to use the problematic PHP version, and investigate what's going on! ### 7. Keeping your Pull Request updated If a maintainer asks you to "rebase" your PR, they're saying that a lot of code has changed, and that you need to update your branch so it's easier to merge. To learn more about rebasing in Git, there are a lot of [good](http://git-scm.com/book/en/Git-Branching-Rebasing) [resources](https://help.github.com/articles/interactive-rebase) but here's the suggested workflow: ```sh git checkout 325-kill-sql-injections git pull --rebase upstream master git push --force-with-lease 325-kill-sql-injections ``` ### 8. Merging a PR (maintainers only) A PR can only be merged into master by a maintainer if: 1. It is passing CI. 2. It has been approved by at least one maintainer. If it was a maintainer who opened the PR, only one extra approval is needed. 3. It has no requested changes. 4. It is up to date with current master. Any maintainer is allowed to merge a PR if all of these conditions are met. ### 9. Shipping a release (maintainers only) Maintainers need to do the following to push out a release: 1. Make sure that all pending and mergeable pull requests are in 2. Close the corresponding [milestone](https://github.com/jvoisin/snuffleupagus/milestones) 2. Run `valgrind` (by adding a `-m` after the `-q` in the Makefile) and check that everything is ok. Don't mind the python-related issues. 2. Run `cd src; phpize; ./configure --enable-snuffleupagus --enable-debug; scan-build make` and fix the possible issues. 3. Update the `src/php_snuffleupagus.h` according to [semantic versioning](https://semver.org/) 4. Update the changelog page in the documentation 5. Update the Debian changelog in `./debian/changelog` with `cd debian; dch` 6. Commit the result 7. Clean up the folder `make clean; git clean -xdf` 8. Create a tag for the release: ```sh git tag -s v$MAJOR.$MINOR.$PATCH -m "v$MAJOR.$MINOR.$PATCH" git push --tags git push origin master ``` 9. Wait for the CI on the new tag branch to finish 10. Create the [release on github](https://github.com/jvoisin/snuffleupagus/releases) 11. Add the freshly built Debian packages from the CI to the release 12. Do the *secret release dance* alt-php80-snuffleupagus/README.md000064400000014667150043501310012433 0ustar00


Snuffleupagus' logo
Snuffleupagus

Security module for php7 and php8 - Killing bugclasses and virtual-patching the rest!

Testing PHP7 on various Linux distributions Testing PHP8 on various Linux distributions Coverity CII Best Practises readthedocs.org coveralls twitter Packaging status CodeQL

Key Features • Download • Examples • Documentation • License • Thanks

Snuffleupagus is a [PHP 7+ and 8+](https://secure.php.net/) module designed to drastically raise the cost of attacks against websites, by killing entire bug classes. It also provides a powerful virtual-patching system, allowing administrator to fix specific vulnerabilities and audit suspicious behaviours without having to touch the PHP code. ## Key Features * No [noticeable performance impact](https://dustri.org/b/snuffleupagus-030-dentalium-elephantinum.html) * Powerful yet simple to write virtual-patching rules * Killing several classes of vulnerabilities * [Unserialize-based](https://www.owasp.org/images/9/9e/Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits.pdf) code execution * [`mail`-based]( https://blog.ripstech.com/2016/roundcube-command-execution-via-email/ ) code execution * Cookie-stealing [XSS]( https://en.wikipedia.org/wiki/Cross-site_scripting ) * File-upload based code execution * Weak PRNG * [XXE]( https://en.wikipedia.org/wiki/XML_external_entity_attack ) * Filter based remote code execution and assorted shenanigans * Several hardening features * Automatic `secure` and `samesite` flag for cookies * Bundled set of rules to detect post-compromissions behaviours * Global [strict mode]( https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations) and type-juggling prevention * Whitelisting of [stream wrappers](https://secure.php.net/manual/en/intro.stream.php) * Preventing writeable files execution * Whitelist/blacklist for `eval` * Enforcing TLS certificate validation when using [curl](https://secure.php.net/manual/en/book.curl.php) * Request dumping capability * A relatively sane code base: * A [comprehensive](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master) test suite close to 100% coverage * Every commit is tested on [several distributions](https://gitlab.com/jvoisin/snuffleupagus/pipelines) * An `clang-format`-enforced code style * A [comprehensive documentation](https://snuffleupagus.rtfd.io) * Usage of [coverity](https://scan.coverity.com/projects/jvoisin-snuffleupagus), codeql, [scan-build](https://clang-analyzer.llvm.org/scan-build.html), … ## Download We've got a [download page](https://snuffleupagus.readthedocs.io/download.html), where you can find packages for your distribution, but you can of course just `git clone` this repo, or check the releases on [github](https://github.com/jvoisin/snuffleupagus/releases). ## Examples We're providing [various example rules](https://github.com/jvoisin/snuffleupagus/tree/master/config), that are looking like this: ```python # Harden the `chmod` function sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop(); # Mitigate command injection in `system` sp.disable_function.function("system").param("command").value_r("[$|;&`\\n]").drop(); ``` Upon violation of a rule, you should see lines like this in your logs: ```python [snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in /var/www/index.php:2, because the return value (0) of the function 'strpos' matched a rule. ``` ## Documentation We've got a [comprehensive website](https://snuffleupagus.readthedocs.io/) with all the documentation that you could possibly wish for. You can of course [build it yourself](https://github.com/jvoisin/snuffleupagus/tree/master/doc). ## Thanks Many thanks to: - The [Suhosin project](https://suhosin.org) for being a __huge__ source of inspiration - [NBS System](https://www.nbs-system.com) for initially sponsoring the development - [Suhosin-ng](https://github.com/sektioneins/suhosin-ng) for their [experimentations](https://github.com/sektioneins/suhosin-ng/wiki/News) and [contributions](https://github.com/jvoisin/snuffleupagus/commits?author=bef), as well as [NLNet](https://nlnet.nl/project/Suhosin-NG/) for sponsoring it - All [our contributors](https://github.com/jvoisin/snuffleupagus/graphs/contributors)