debian/0000755000000000000000000000000012267045571007177 5ustar debian/rss.xsl0000644000000000000000000000162512267045571010542 0ustar

Date of publication:

  • Date:

  • debian/spotweb.config0000644000000000000000000000072012267045571012050 0ustar #!/bin/sh # config maintainer script for spotweb set -e # source debconf stuff . /usr/share/debconf/confmodule # source dbconfig-common shell library, and call the hook function if [ -f /usr/share/dbconfig-common/dpkg/config.mysql ]; then . /usr/share/dbconfig-common/dpkg/config.mysql dbc_dbtypes="mysql" dbc_install='true' dbc_upgrade='true' dbc_remove='true' dbc_go spotweb $@ fi db_go || true #DEBHELPER# debian/TODO0000644000000000000000000000112712267045571007670 0ustar TODO for Debian spotweb package - Maybe: start an initial retrieve after installation. Possibly ask about this in debconf - After each new upstream version: + Check copyright notices, esp. for embedded libraries + Remove possibly non-free stuff from libraries etc. in dfsg branch and get-orig-source script + Check if new embedded library is already in Debian + Update Debian patches + Check for extra intermediate database updates + make sure apt-get upgrade, purge, re-install all work for reasonable upgrade paths + fixup get-orig-source script and debian/README.source debian/changelog0000644000000000000000000000601212267045571011050 0ustar spotweb (20130826+dfsg2-2) unstable; urgency=low * Use 'localhost' for database host if not set by dbconfig-common. Closes: #736111 -- Jan-Pascal van Best Sun, 19 Jan 2014 22:58:44 +0100 spotweb (20130826+dfsg2-1) unstable; urgency=low * New upstream version (v20130826) * Updated debian/copyright * Update README.source and get-orig-source * Add upstream changelog * Updates for Apache 2.4 configuration snippets. Closes: #669806 * Use Debian-supplied jquery-form javascript library instead of upstream embedded version. * Remove upstream embedded font files, use Debian-packaged fonts instead. * The news server information is now maintained in the spotweb database, and not in the configuration files. That means you will need to configure your news server information again (admin/config/settings/newsservers). * Disable Notifo notifications, the service has been discontinued. * Do not exit postinst script with error if database update fails. Closes: #709877 * Have dbconfig-common handle database upgrades * Fix for database update on package upgrade * Removed debian/po, not needed any more. Closes: #662123, #718528 * Change dependency to fonts-liberation. Closes: #722404 * Fix patch 0007 which prevented a fresh install, thanks to Henkjan Gersen for catching this. * Update Apache configuration file to provide newznab provider urls. -- Jan-Pascal van Best Fri, 17 Jan 2014 11:51:12 +0100 spotweb (20111002+dfsg-4.1) unstable; urgency=low * Non-maintainer upload. * spotweb.cron.hourly: Gracefully skip the cronjob with an exit code of 0 after the package was removed. (Closes: #663030) -- Andreas Beckmann Sun, 03 Feb 2013 23:09:14 +0100 spotweb (20111002+dfsg-4) unstable; urgency=low * Update Dutch debconf translation -- Jan-Pascal van Best Tue, 10 Jan 2012 15:51:46 +0100 spotweb (20111002+dfsg-3) unstable; urgency=low * Debconf templates and debian/control reviewed by the debian-l10n- english team as part of the Smith review project. Closes: #646747 * [Debconf translation updates] * Swedish (Martin Bagge / brother). Closes: #649453 * German (Erik Pfannenstein). Closes: #650007 * Russian (Yuri Kozlov). Closes: #650161 * French (Julien Patriarca). Closes: #650295 * Czech (Michal Simunek). Closes: #650679 * Portuguese (Miguel Figueiredo). Closes: #650765 * Spanish; (Francisco Javier Cuadrado). Closes: #650769 * Danish (Joe Hansen). Closes: #650843 -- Jan-Pascal van Best Fri, 30 Dec 2011 20:21:08 +0100 spotweb (20111002+dfsg-2) unstable; urgency=low * Updated dependency on msttcorefonts->ttf-liberation * Updated bundled jquery.dynatree version to 1.2.0 -- Jan-Pascal van Best Tue, 25 Oct 2011 09:47:41 +0200 spotweb (20111002+dfsg-1) unstable; urgency=low * Initial release (Closes: #638446). -- Jan-Pascal van Best Mon, 03 Oct 2011 07:48:30 +0200 debian/spotweb.docs0000644000000000000000000000004412267045571011532 0ustar INSTALL README.md notifications.xml debian/README.Debian0000644000000000000000000000114612267045571011242 0ustar spotweb notes for Debian ------------------------ After installation, Spotweb is available as a web application on http:///spotweb. Please adapt /etc/spotweb/apache.conf if you need it to appear somewhere else. This package installs an hourly cron job to automatically update the spots database. The cron job logs to /var/log/spotweb.log. At each install, upgrade or downgrade of this package, the database structure is updated automatically. This may cause trouble if you install, downgrade and then upgrade again. -- Jan-Pascal van Best , Tue, 04 Oct 2011 12:59:37 +0200 debian/retrieve.sh0000755000000000000000000000021712267045571011363 0ustar #!/bin/sh php5 --define include_path=".:/usr/share/spotweb:/etc/spotweb:/usr/share/php" \ /usr/share/spotweb/scripts/retrieve.php --force debian/control0000644000000000000000000000250412267045571010603 0ustar Source: spotweb Section: web Priority: optional Maintainer: Jan-Pascal van Best Build-Depends: debhelper (>= 9.0.0), po-debconf, yui-compressor (>= 2.4.2), dh-apache2, xsltproc Standards-Version: 3.9.5 Homepage: https://github.com/spotweb/spotweb Vcs-Git: git://anonscm.debian.org/users/janpascal-guest/spotweb.git Vcs-Browser: http://anonscm.debian.org/gitweb/?p=users/janpascal-guest/spotweb.git Package: spotweb Architecture: all Depends: ${misc:Depends}, dbconfig-common, mysql-client, ucf, libapache2-mod-php5 | php5, php5-mysql | php5-mysqlnd, php5-curl, php-net-nntp (>= 1.5.0~rc1), php5-gmp, php5-gd, php5-json, fonts-liberation, libjs-jquery (>= 1.6.2), libjs-jquery-fancybox, libjs-jquery-cookie, libjs-jquery-mousewheel, libjs-jquery-easing, libjs-jquery-ui (>= 1.8.ooops.14), libjs-jquery-form Recommends: mysql-server, apache2 | httpd, ${misc:Recommends} Suggests: sabnzbdplus, nzbget Description: web interface to search and filter Usenet spots SpotWeb is a web-based version of the decentralized news-indexing system SpotNet, which fetches Usenet "spots" - postings that contain information about uploaded binaries. SpotWeb allows searching, filtering, and viewing of the spots and comments. It integrates with NZB downloaders such as NZBget and SABnzbd+ to download the binaries from Usenet. debian/upgrade-db.sh0000755000000000000000000000021112267045571011542 0ustar #!/bin/sh php5 --define include_path=".:/usr/share/spotweb:/etc/spotweb:/usr/share/php" \ /usr/share/spotweb/scripts/upgrade-db.php debian/README.source0000644000000000000000000000227312267045571011362 0ustar README.source for spotweb ------------------------- The upstream source is taken from github, https://github.com/spotweb/spotweb The debian/rules target 'get-orig-source' downloads the upstream source, removes an embedded non-free font file and a number of compressed js and css files and the embedded Net:NNTP PHP Pear library, and repacks the source into the Debian orig.tar.gz. See the debian/get-orig-source.sh script for details. This Debian package rearranges the location where the components of spotweb are installed, to make sure only the necessarily web-accessible files are exposed directly through the web server. The packaging ignores the upstream-bundled versions of php-net-nntp, libjs-jquery, libjs-jquery-fancybox, libjs-jquery-cookie, libjs-jquery-mousewheel, libjs-jquery-easing and libjs-jquery-ui and libjs-jquery-form. It uses the Debian-packaged libraries instead. In the Debian source under debian/extra_sources are supplied three javascript files that are bundled in the upstream source in compressed form. During the package build these files are compressed and installed in the proper location. -- Jan-Pascal van Best , Tue, 04 Oct 2011 13:05:56 +0200 debian/spotweb.postrm0000755000000000000000000000443212267045571012136 0ustar #!/bin/sh # postrm script for spotweb # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package if [ -f /usr/share/debconf/confmodule ]; then . /usr/share/debconf/confmodule fi if [ -f /usr/share/dbconfig-common/dpkg/postrm.mysql ]; then . /usr/share/dbconfig-common/dpkg/postrm.mysql dbc_go spotweb $@ fi CONF="spotweb" COMMON_STATE=$(dpkg-query -f '${Status}' -W 'apache2.2-common' 2>/dev/null | awk '{print $3}' || true) case "$1" in purge) if [ -e /usr/share/apache2/apache2-maintscript-helper ] ; then . /usr/share/apache2/apache2-maintscript-helper apache2_invoke disconf $CONF || exit $? elif [ "$COMMON_STATE" = "installed" ] || [ "$COMMON_STATE" = "unpacked" ] ; then [ ! -L /etc/apache2/conf.d/$CONF.conf ] || rm /etc/apache2/conf.d/$CONF.conf fi rm -f /etc/spotweb/dbconfig.php rm -f /etc/spotweb/nntpconfig.php if which ucf >/dev/null 2>&1; then ucf --purge /etc/spotweb/dbconfig.php ucf --purge /etc/spotweb/nntpconfig.php fi ;; remove) if [ -e /usr/share/apache2/apache2-maintscript-helper ] ; then . /usr/share/apache2/apache2-maintscript-helper apache2_invoke disconf $CONF || exit $? elif [ "$COMMON_STATE" = "installed" ] || [ "$COMMON_STATE" = "unpacked" ] ; then [ ! -L /etc/apache2/conf.d/$CONF.conf ] || rm /etc/apache2/conf.d/$CONF.conf fi ;; upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 debian/spotweb.cron.hourly0000755000000000000000000000020412267045571013065 0ustar #!/bin/sh test -x /usr/share/spotweb/scripts/retrieve.sh || exit 0 /usr/share/spotweb/scripts/retrieve.sh >> /var/log/spotweb.log debian/spotweb.logrotate0000644000000000000000000000023112267045571012600 0ustar /var/log/spotweb.log { rotate 7 daily compress delaycompress copytruncate missingok notifempty } debian/NEWS0000644000000000000000000000076212267045571007703 0ustar spotweb (20130826+dfsg2-1) unstable; urgency=low The configuration of the news (nntp) servers in Spotweb has moved from configuration files to the database. This is not handled automatically. If you upgrade from a previous version of Spotweb, you will need to reconfigure your news server settings, by logging in as the 'admin' user and setting the news servers in the config/settings menu in Spotweb. -- Jan-Pascal van Best Mon, 26 Aug 2013 20:04:08 +0200 debian/spotweb.links0000644000000000000000000000011512267045571011721 0ustar /usr/share/spotweb/www/images/favicon.ico /usr/share/spotweb/www/favicon.ico debian/copyright0000644000000000000000000002216412267045571011137 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: spotweb Upstream-Contact: Spotweb Source: https://github.com/spotweb/spotweb Files: * debian/db-update/v20111210/* Copyright: Copyright 2010-2013 Spotweb License: BSD-3-clause 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. * Neither the name of the Spotweb team nor the names of its contributors may 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 HOLDER 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. Files: js/dynatree/* Copyright: Copyright 2008-2011 Martin Wendt (http://dynatree.googlecode.com/) License: Expat or GPL-2 Files: js/jquery/jquery.hotkeys.js Copyright: Copyright 2010 John Resig License: Expat or GPL-2 Files: js/jquery/jquery.form.js Copyright: Copyright 2009-2011 Mike Alsup, John Resig, Mike Alsup, Mark Constable, Klaus Hartl, Matt Grimm, Yehuda Katz, Jörn Zaefferer, Sam Collett, Gilles van den Hoven, Kevin Glowacz, Alex Andrienko License: Expat or GPL-2 Files: js/jquery.mobile-1.0a3/* Copyright: Copyright 2010 jQuery Project Copyright 2010 "Cowboy" Ben Alman License: Expat or GPL-2 Files: js/jquery-json/* Copyright: Copyright 2011 Brantley Harris License: Expat Files: js/sha1/* Copyright: Muhammad Hussein Fattahizadeh < muhammad [AT] semnanweb [DOT] com >A License: GPL-3 Files: lib/gettext/* Copyright: Copyright (c) 2009 David Soria Parra License: Expat Files: lib/images/pchart/* Copyright: Copyright (c) 2011 Jean-Damien POGOLOTTI License: GPL-3 Files: lib/notifications/boxcar/* Copyright: Copyright (c) 2010, UKD1 Limited License: ISC Files: lib/notifications/growl/* Copyright: Copyright 2007-2011 Tyler Hall License: Expat Files: lib/notifications/nma/* Copyright: Copyright 2011, Adriano Maia. License: Expat Files: lib/notifications/prowl/* Copyright: Copyright 2011 Mario Mueller License: Apache-2 Files: lib/notifications/twitter/* Copyright: Copyright (c) 2009 Abraham Williams - http://abrah.am - abraham@poseurte.ch License: Expat Files: Crypt/* debian/db-update/v20111210/Crypt/* Copyright: Copyright 2009-2010 Jim Wigginton License: LGPL-2.1+ Files: Mobile_Detect.php Copyright: Copyright 2009 vic.stanciu@gmail.com License: Expat Files: Math/BigInteger.php debian/db-update/v20111210/Math/BigInteger.php Copyright: Copyright 2010 Jim Wigginton License: LGPL-2.1+ Files: debian/* Copyright: Copyright 2011 Jan-Pascal van Best License: Expat Files: debian/extra_sources/jquery.address-1.4.js Copyright: Copyright (c) 2009-2010 Rostislav Hristov License: Expat or GPL-2 Files: debian/extra_sources/jquery.dynatree.js Copyright: Copyright (c) 2008-2011, Martin Wendt (http://wwWendt.de) License: Expat or GPL-2 Files: debian/extra_sources/jquery.preload.js Copyright: Copyright 2008 Ariel Flesler - aflesler(at)gmail(dot)com License: Expat or GPL-2 License: Apache-2 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. . On Debian systems, the complete text of the Apache License, version 2.0, can be found in the `/usr/share/common-licenses/Apache-2.0' file. License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License: GPL-2 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,i 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 Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. . On Debian systems, the complete text of the GNU General Public License, version 2, can be found in the '/usr/share/common-licenses/GPL-2' file. License: GPL-3 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 3 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, see . . On Debian systems, the complete text of the GNU General Public License, version 3, can be found in the '/usr/share/common-licenses/GPL-3' file. License: LGPL-2.1+ LICENSE: This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. . This library 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 Lesser General Public License for more details. . You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. . On Debian systems, the complete text of the GNU Lesser General Public License, version 2.1, can be found in the '/usr/share/common-licenses/LGPL-2.1' file. License: ISC Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. . THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. debian/spotweb.prerm0000755000000000000000000000172012267045571011734 0ustar #!/bin/sh # prerm script for spotweb # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `upgrade' # * `failed-upgrade' # * `remove' `in-favour' # * `deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package . /usr/share/debconf/confmodule . /usr/share/dbconfig-common/dpkg/prerm.mysql dbc_go spotweb $@ case "$1" in remove|upgrade|deconfigure) ;; failed-upgrade) ;; *) echo "prerm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 debian/spotweb.install0000644000000000000000000000073712267045571012261 0ustar index.php /usr/share/spotweb/www Mobile_Detect.php /usr/share/spotweb/www images /usr/share/spotweb/www settings.php /etc/spotweb/ debian/dbsettings.inc.php /etc/spotweb/ retrieve.php /usr/share/spotweb/scripts upgrade-db.php /usr/share/spotweb/scripts lib /usr/share/spotweb/ Crypt /usr/share/spotweb Math /usr/share/spotweb templates /usr/share/spotweb js /usr/share/spotweb debian/retrieve.sh /usr/share/spotweb/scripts debian/db-update/v20111210 /usr/share/spotweb/db-update debian/db-update/0000755000000000000000000000000012267045571011044 5ustar debian/db-update/v20111210/0000755000000000000000000000000012267045571012121 5ustar debian/db-update/v20111210/upgrade-db.php0000644000000000000000000000255212267045571014650 0ustar database(); echo "Schema update done" . PHP_EOL; echo "Updating settings" . PHP_EOL; $spotUpgrader->settings($settings); echo "Settings update done" . PHP_EOL; $spotUpgrader->users($settings); echo "Updating users" . PHP_EOL; echo "Users' update done" . PHP_EOL; echo "Performing basic analysis of database tables" . PHP_EOL; $spotUpgrader->analyze($settings); echo "Basic database optimalisation done" . PHP_EOL; } catch(Exception $x) { echo PHP_EOL . PHP_EOL; echo 'SpotWeb crashed' . PHP_EOL . PHP_EOL; echo "Database schema of settings upgrade mislukt:" . PHP_EOL; echo " " . $x->getMessage() . PHP_EOL; echo PHP_EOL . PHP_EOL; echo $x->getTraceAsString(); die(1); } # catch debian/db-update/v20111210/settings.php0000644000000000000000000002253412267045571014500 0ustar 1, 'prio' => 1), Array('groupid' => 2, 'prio' => 2) ); # Cookie host if (isset($_SERVER['HTTP_HOST'])) { // Strip leading periods $cookie_domain = ltrim($_SERVER['HTTP_HOST'], '.'); // Strip www. if (strpos($cookie_domain, 'www.') === 0) { $cookie_domain = substr($cookie_domain, 4); } //Strip port numbers $cookie_domain = explode(':', $cookie_domain); $cookie_domain = '.' . $cookie_domain[0]; } # if // Per RFC 2109, cookie domains must contain at least one dot other than the // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain. if (isset($cookie_domain) && count(explode('.', $cookie_domain)) > 2 && !filter_var(ltrim($cookie_domain, '.'), FILTER_VALIDATE_IP)) { $settings['cookie_host'] = $cookie_domain; unset($cookie_domain); } else { $settings['cookie_host'] = ''; } # else # vertaal de categorieen uit spots (zie SpotCategories.php) naar sabnzbd categorieen $settings['sabnzbd']['categories'] = Array( 0 => Array('default' => "movies", # Default categorie als niets anders matched 'a5' => "books", 'd2' => "anime", 'd11' => "tv", 'd29' => "anime"), 1 => Array('default' => 'music'), 2 => Array('default' => 'games'), 3 => Array('default' => 'apps', 'a3' => 'consoles', 'a3' => 'consoles', 'a4' => 'consoles', 'a5' => 'consoles', 'a6' => 'consoles', 'a7' => 'consoles', 'a8' => 'consoles', 'a9' => 'consoles', 'a10' => 'consoles', 'a11' => 'consoles', 'a12' => 'consoles', 'a13' => 'pda', 'a14' => 'pda', 'a15' => 'pda') ); # Als een user niet expliciet geauthenticeerd is, dan wordt deze user standaard ingelogged # met een userid van 1 -- dit is de builtin anonymous user. Als je je Spotweb installatie # helemaal alleen gebruikt, kan je dit eventueel laten herleiden naar een andere user zodat # je Spotweb volledig kan gebruiken (inclusief posten van comments en dergelijke) zonder # dat je ooit hoeft in te loggen. $settings['nonauthenticated_userid'] = 1; # # Include eventueel eigen settings, dit is ook een PHP file. # Settings welke hierin staan zullen de instellingen van deze file overiden. # # We raden aan om je instellingen in deze eigen file te zetten zodat bij een upgrade # je instellingen bewaard blijven. # if (@file_exists('../ownsettings.php')) { include_once('../ownsettings.php'); } # <== deze lijn mag je eventueel verwijderen if (file_exists('ownsettings.php')) { include_once('ownsettings.php'); } # <== deze lijn mag je eventueel verwijderen # QuickLinks, we testen eerst of hij niet al door iemand anders is gezet in ownsettings.php en # anders vullen we hem zelf op. We kunnen dit niet boven ownsettings.php plaatsen want dan missen # we de keep_watchlist en keep_downloadlist settings. if (!isset($settings['quicklinks'])) { $settings['quicklinks'] = Array(); $settings['quicklinks'][] = Array('Reset filters', "home", "?search[tree]=&search[unfiltered]=true", "", Array(SpotSecurity::spotsec_view_spots_index, ''), null); $settings['quicklinks'][] = Array('Nieuw', "today", "?search[tree]=&search[unfiltered]=true&search[value][]=New:0", "", Array(SpotSecurity::spotsec_keep_own_seenlist, ''), 'count_newspots'); $settings['quicklinks'][] = Array('Watchlist', "fav", "?search[tree]=&search[unfiltered]=true&search[value][]=Watch:0", "", Array(SpotSecurity::spotsec_keep_own_watchlist, ''), 'keep_watchlist'); $settings['quicklinks'][] = Array('Gedownload', "download", "?search[tree]=&search[unfiltered]=true&search[value][]=Downloaded:0", "", Array(SpotSecurity::spotsec_keep_own_downloadlist, ''), 'keep_downloadlist'); $settings['quicklinks'][] = Array('Recent bekeken', "eye", "?search[tree]=&search[unfiltered]=true&search[value][]=Seen:0", "", Array(SpotSecurity::spotsec_keep_own_seenlist, ''), 'keep_seenlist'); $settings['quicklinks'][] = Array('Mijn spots', "fav", "?search[tree]=&search[unfiltered]=true&search[value][]=MyPostedSpots:0", "", Array(SpotSecurity::spotsec_post_spot, ''), null); $settings['quicklinks'][] = Array('Statistieken', "stats", "?page=statistics", "", Array(SpotSecurity::spotsec_view_statistics, ''), null); $settings['quicklinks'][] = Array('Documentatie', "help", "https://github.com/spotweb/spotweb/wiki", "external", Array(SpotSecurity::spotsec_view_spots_index, ''), null); } # if isset # # Ga nu de template zetten # if (($settings['templates']['autodetect']) && (isset($_SERVER['HTTP_USER_AGENT'])) && (isset($_SERVER['HTTP_ACCEPT'])) ) { include_once('Mobile_Detect.php'); $detect = new Mobile_Detect(); if ($detect->isMobile()) { $settings['tpl_name'] = $settings['templates']['mobile']; } else { $settings['tpl_name'] = $settings['templates']['default']; } # else } else { $settings['tpl_name'] = $settings['templates']['default']; } # else $settings['tpl_name'] = str_replace('templates/', '', $settings['tpl_name']); # Als de OpenSSL module geladen is, moet de openssl_cnf_path naar een # leesbare configuratie file wijzen if ((!is_readable($settings['openssl_cnf_path'])) && (extension_loaded("openssl"))) { die("openssl_cnf_path verwijst niet naar een leesbare OpenSSL configuratie file" . PHP_EOL); } # if # Voeg een sluitende slash toe als die er nog niet is if (substr($settings['spotweburl'], -1) != '/') { $settings['spotweburl'] .= '/'; } # if # Preferences lokaal niet meer toestaan if (isset($settings['prefs']['perpage']) || (isset($settings['prefs']['date_formatting']))) { die("Preferences worden voortaan per user gezet" . PHP_EOL); } # if # deprecated settings niet meer toestaan $ownsettingserror = ''; $array = array('blacklist_url', 'cookie_expires', 'deny_robots', 'enable_stacktrace', 'enable_timing', 'external_blacklist', 'nntp_hdr', 'nntp_nzb', 'nntp_post', 'prefetch_image', 'prefetch_nzb', 'retention', 'retrieve_comments', 'retrieve_full', 'retrieve_full_comments', 'retrieve_increment', 'retrieve_newer_than', 'retrieve_reports', 'sendwelcomemail', 'spot_moderation'); foreach ($array as $value) { if (isset($settings[$value])) { $ownsettingserror .= $value . " wordt voortaan in de db bijgehouden" . PHP_EOL; } # if } # foreach $array = array('allow_user_template', 'auto_markasread', 'filters', 'index_filter', 'keep_downloadlist', 'keep_watchlist', 'nzb_search_engine', 'nzbhandling', 'show_multinzb'); foreach ($array as $value) { if (isset($settings[$value])) { $ownsettingserror .= $value . " is een user preference geworden" . PHP_EOL; } # if } # foreach $array = array('count_newspots', 'keep_seenlist'); foreach ($array as $value) { if (isset($settings[$value])) { $ownsettingserror .= $value . " is een user preference geworden (en afschermbaar via het rechtensysteem)" . PHP_EOL; } # if } # foreach $array = array('show_nzbbutton', 'show_updatebutton'); foreach ($array as $value) { if (isset($settings[$value])) { $ownsettingserror .= $value . " is een user right geworden" . PHP_EOL; } # if } # foreach if (!empty($ownsettingserror)) { if (isset($_SERVER['SERVER_PROTOCOL'])) { echo "
    "; }
    	die($ownsettingserror . PHP_EOL . "Haal bovenstaande settings weg uit je ownsettings.php" . PHP_EOL);
    } # if
    
    # Controleer op oud type quicklinks (zonder security)
    foreach($settings['quicklinks'] as $link) {
    	if (count($link) < 5) {
    		die("Quicklinks moeten voortaan ook een security check bevatten, wijzig je quicklinks in je (own)settings.php (zie settings.php voor een voorbeeld)");
    	} # if
    } # foreach
    
    # Controleer op oud type quicklinks (zonder preference link)
    foreach($settings['quicklinks'] as $link) {
    	if (count($link) < 6) {
    		die("Quicklinks moeten voortaan ook een voorkeuren check bevatten, wijzig je quicklinks in je (own)settings.php (zie settings.php voor een voorbeeld)");
    	} # if
    } # foreach
    debian/db-update/v20111210/Math/0000755000000000000000000000000012267045571013012 5ustar  debian/db-update/v20111210/Math/BigInteger.php0000644000000000000000000035527612267045571015564 0ustar  > and << cannot be used, nor can the modulo operator %,
     * which only supports integers.  Although this fact will slow this library down, the fact that such a high
     * base is being used should more than compensate.
     *
     * When PHP version 6 is officially released, we'll be able to use 64-bit integers.  This should, once again,
     * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
     * subtraction).
     *
     * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format.  ie.
     * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
     *
     * Useful resources are as follows:
     *
     *  - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
     *  - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
     *  - Java's BigInteger classes.  See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
     *
     * Here's an example of how to use this library:
     * 
     * add($b);
     *
     *    echo $c->toString(); // outputs 5
     * ?>
     * 
     *
     * LICENSE: This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 2.1 of the License, or (at your option) any later version.
     *
     * This library 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
     * Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
     * MA  02111-1307  USA
     *
     * @category   Math
     * @package    Math_BigInteger
     * @author     Jim Wigginton 
     * @copyright  MMVI Jim Wigginton
     * @license    http://www.gnu.org/licenses/lgpl.txt
     * @version    $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $
     * @link       http://pear.php.net/package/Math_BigInteger
     */
    
    /**#@+
     * Reduction constants
     *
     * @access private
     * @see Math_BigInteger::_reduce()
     */
    /**
     * @see Math_BigInteger::_montgomery()
     * @see Math_BigInteger::_prepMontgomery()
     */
    define('MATH_BIGINTEGER_MONTGOMERY', 0);
    /**
     * @see Math_BigInteger::_barrett()
     */
    define('MATH_BIGINTEGER_BARRETT', 1);
    /**
     * @see Math_BigInteger::_mod2()
     */
    define('MATH_BIGINTEGER_POWEROF2', 2);
    /**
     * @see Math_BigInteger::_remainder()
     */
    define('MATH_BIGINTEGER_CLASSIC', 3);
    /**
     * @see Math_BigInteger::__clone()
     */
    define('MATH_BIGINTEGER_NONE', 4);
    /**#@-*/
    
    /**#@+
     * Array constants
     *
     * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
     * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
     *
     * @access private
     */
    /**
     * $result[MATH_BIGINTEGER_VALUE] contains the value.
     */
    define('MATH_BIGINTEGER_VALUE', 0);
    /**
     * $result[MATH_BIGINTEGER_SIGN] contains the sign.
     */
    define('MATH_BIGINTEGER_SIGN', 1);
    /**#@-*/
    
    /**#@+
     * @access private
     * @see Math_BigInteger::_montgomery()
     * @see Math_BigInteger::_barrett()
     */
    /**
     * Cache constants
     *
     * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
     */
    define('MATH_BIGINTEGER_VARIABLE', 0);
    /**
     * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
     */
    define('MATH_BIGINTEGER_DATA', 1);
    /**#@-*/
    
    /**#@+
     * Mode constants.
     *
     * @access private
     * @see Math_BigInteger::Math_BigInteger()
     */
    /**
     * To use the pure-PHP implementation
     */
    define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
    /**
     * To use the BCMath library
     *
     * (if enabled; otherwise, the internal implementation will be used)
     */
    define('MATH_BIGINTEGER_MODE_BCMATH', 2);
    /**
     * To use the GMP library
     *
     * (if present; otherwise, either the BCMath or the internal implementation will be used)
     */
    define('MATH_BIGINTEGER_MODE_GMP', 3);
    /**#@-*/
    
    /**
     * The largest digit that may be used in addition / subtraction
     *
     * (we do pow(2, 52) instead of using 4503599627370496, directly, because some PHP installations
     *  will truncate 4503599627370496)
     *
     * @access private
     */
    define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52));
    
    /**
     * Karatsuba Cutoff
     *
     * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
     *
     * @access private
     */
    define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
    
    /**
     * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
     * numbers.
     *
     * @author  Jim Wigginton 
     * @version 1.0.0RC4
     * @access  public
     * @package Math_BigInteger
     */
    class Math_BigInteger {
        /**
         * Holds the BigInteger's value.
         *
         * @var Array
         * @access private
         */
        var $value;
    
        /**
         * Holds the BigInteger's magnitude.
         *
         * @var Boolean
         * @access private
         */
        var $is_negative = false;
    
        /**
         * Random number generator function
         *
         * @see setRandomGenerator()
         * @access private
         */
        var $generator = 'mt_rand';
    
        /**
         * Precision
         *
         * @see setPrecision()
         * @access private
         */
        var $precision = -1;
    
        /**
         * Precision Bitmask
         *
         * @see setPrecision()
         * @access private
         */
        var $bitmask = false;
    
        /**
         * Mode independant value used for serialization.
         *
         * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for 
         * a variable that'll be serializable regardless of whether or not extensions are being used.  Unlike $this->value,
         * however, $this->hex is only calculated when $this->__sleep() is called.
         *
         * @see __sleep()
         * @see __wakeup()
         * @var String
         * @access private
         */
        var $hex;
    
        /**
         * Converts base-2, base-10, base-16, and binary strings (eg. base-256) to BigIntegers.
         *
         * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
         * two's compliment.  The sole exception to this is -10, which is treated the same as 10 is.
         *
         * Here's an example:
         * 
         * toString(); // outputs 50
         * ?>
         * 
         *
         * @param optional $x base-10 number or base-$base number if $base set.
         * @param optional integer $base
         * @return Math_BigInteger
         * @access public
         */
        function Math_BigInteger($x = 0, $base = 10)
        {
            if ( !defined('MATH_BIGINTEGER_MODE') ) {
                switch (true) {
                    case extension_loaded('gmp'):
                        define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
                        break;
                    case extension_loaded('bcmath'):
                        define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
                        break;
                    default:
                        define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
                }
            }
    
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
                        $this->value = $x;
                        return;
                    }
                    $this->value = gmp_init(0);
                    break;
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $this->value = '0';
                    break;
                default:
                    $this->value = array();
            }
    
            if (empty($x)) {
                return;
            }
    
            switch ($base) {
                case -256:
                    if (ord($x[0]) & 0x80) {
                        $x = ~$x;
                        $this->is_negative = true;
                    }
                case  256:
                    switch ( MATH_BIGINTEGER_MODE ) {
                        case MATH_BIGINTEGER_MODE_GMP:
                            $sign = $this->is_negative ? '-' : '';
                            $this->value = gmp_init($sign . '0x' . bin2hex($x));
                            break;
                        case MATH_BIGINTEGER_MODE_BCMATH:
                            // round $len to the nearest 4 (thanks, DavidMJ!)
                            $len = (strlen($x) + 3) & 0xFFFFFFFC;
    
                            $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
    
                            for ($i = 0; $i < $len; $i+= 4) {
                                $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
                                $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
                            }
    
                            if ($this->is_negative) {
                                $this->value = '-' . $this->value;
                            }
    
                            break;
                        // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
                        default:
                            while (strlen($x)) {
                                $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26));
                            }
                    }
    
                    if ($this->is_negative) {
                        if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
                            $this->is_negative = false;
                        }
                        $temp = $this->add(new Math_BigInteger('-1'));
                        $this->value = $temp->value;
                    }
                    break;
                case  16:
                case -16:
                    if ($base > 0 && $x[0] == '-') {
                        $this->is_negative = true;
                        $x = substr($x, 1);
                    }
    
                    $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
    
                    $is_negative = false;
                    if ($base < 0 && hexdec($x[0]) >= 8) {
                        $this->is_negative = $is_negative = true;
                        $x = bin2hex(~pack('H*', $x));
                    }
    
                    switch ( MATH_BIGINTEGER_MODE ) {
                        case MATH_BIGINTEGER_MODE_GMP:
                            $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
                            $this->value = gmp_init($temp);
                            $this->is_negative = false;
                            break;
                        case MATH_BIGINTEGER_MODE_BCMATH:
                            $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
                            $temp = new Math_BigInteger(pack('H*', $x), 256);
                            $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
                            $this->is_negative = false;
                            break;
                        default:
                            $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
                            $temp = new Math_BigInteger(pack('H*', $x), 256);
                            $this->value = $temp->value;
                    }
    
                    if ($is_negative) {
                        $temp = $this->add(new Math_BigInteger('-1'));
                        $this->value = $temp->value;
                    }
                    break;
                case  10:
                case -10:
                    $x = preg_replace('#^(-?[0-9]*).*#', '$1', $x);
    
                    switch ( MATH_BIGINTEGER_MODE ) {
                        case MATH_BIGINTEGER_MODE_GMP:
                            $this->value = gmp_init($x);
                            break;
                        case MATH_BIGINTEGER_MODE_BCMATH:
                            // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
                            // results then doing it on '-1' does (modInverse does $x[0])
                            $this->value = (string) $x;
                            break;
                        default:
                            $temp = new Math_BigInteger();
    
                            // array(10000000) is 10**7 in base-2**26.  10**7 is the closest to 2**26 we can get without passing it.
                            $multiplier = new Math_BigInteger();
                            $multiplier->value = array(10000000);
    
                            if ($x[0] == '-') {
                                $this->is_negative = true;
                                $x = substr($x, 1);
                            }
    
                            $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT);
    
                            while (strlen($x)) {
                                $temp = $temp->multiply($multiplier);
                                $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256));
                                $x = substr($x, 7);
                            }
    
                            $this->value = $temp->value;
                    }
                    break;
                case  2: // base-2 support originally implemented by Lluis Pamies - thanks!
                case -2:
                    if ($base > 0 && $x[0] == '-') {
                        $this->is_negative = true;
                        $x = substr($x, 1);
                    }
    
                    $x = preg_replace('#^([01]*).*#', '$1', $x);
                    $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
    
                    $str = '0x';
                    while (strlen($x)) {
                        $part = substr($x, 0, 4);
                        $str.= dechex(bindec($part));
                        $x = substr($x, 4);
                    }
    
                    if ($this->is_negative) {
                        $str = '-' . $str;
                    }
    
                    $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
                    $this->value = $temp->value;
                    $this->is_negative = $temp->is_negative;
    
                    break;
                default:
                    // base not supported, so we'll let $this == 0
            }
        }
    
        /**
         * Converts a BigInteger to a byte string (eg. base-256).
         *
         * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
         * saved as two's compliment.
         *
         * Here's an example:
         * 
         * toBytes(); // outputs chr(65)
         * ?>
         * 
         *
         * @param Boolean $twos_compliment
         * @return String
         * @access public
         * @internal Converts a base-2**26 number to base-2**8
         */
        function toBytes($twos_compliment = false)
        {
            if ($twos_compliment) {
                $comparison = $this->compare(new Math_BigInteger());
                if ($comparison == 0) {
                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
                }
    
                $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
                $bytes = $temp->toBytes();
    
                if (empty($bytes)) { // eg. if the number we're trying to convert is -1
                    $bytes = chr(0);
                }
    
                if (ord($bytes[0]) & 0x80) {
                    $bytes = chr(0) . $bytes;
                }
    
                return $comparison < 0 ? ~$bytes : $bytes;
            }
    
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    if (gmp_cmp($this->value, gmp_init(0)) == 0) {
                        return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
                    }
    
                    $temp = gmp_strval(gmp_abs($this->value), 16);
                    $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
                    $temp = pack('H*', $temp);
    
                    return $this->precision > 0 ?
                        substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
                        ltrim($temp, chr(0));
                case MATH_BIGINTEGER_MODE_BCMATH:
                    if ($this->value === '0') {
                        return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
                    }
    
                    $value = '';
                    $current = $this->value;
    
                    if ($current[0] == '-') {
                        $current = substr($current, 1);
                    }
    
                    while (bccomp($current, '0', 0) > 0) {
                        $temp = bcmod($current, '16777216');
                        $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
                        $current = bcdiv($current, '16777216', 0);
                    }
    
                    return $this->precision > 0 ?
                        substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
                        ltrim($value, chr(0));
            }
    
            if (!count($this->value)) {
                return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
            }
            $result = $this->_int2bytes($this->value[count($this->value) - 1]);
    
            $temp = $this->copy();
    
            for ($i = count($temp->value) - 2; $i >= 0; --$i) {
                $temp->_base256_lshift($result, 26);
                $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
            }
    
            return $this->precision > 0 ?
                str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
                $result;
        }
    
        /**
         * Converts a BigInteger to a hex string (eg. base-16)).
         *
         * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
         * saved as two's compliment.
         *
         * Here's an example:
         * 
         * toHex(); // outputs '41'
         * ?>
         * 
         *
         * @param Boolean $twos_compliment
         * @return String
         * @access public
         * @internal Converts a base-2**26 number to base-2**8
         */
        function toHex($twos_compliment = false)
        {
            return bin2hex($this->toBytes($twos_compliment));
        }
    
        /**
         * Converts a BigInteger to a bit string (eg. base-2).
         *
         * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
         * saved as two's compliment.
         *
         * Here's an example:
         * 
         * toBits(); // outputs '1000001'
         * ?>
         * 
         *
         * @param Boolean $twos_compliment
         * @return String
         * @access public
         * @internal Converts a base-2**26 number to base-2**2
         */
        function toBits($twos_compliment = false)
        {
            $hex = $this->toHex($twos_compliment);
            $bits = '';
            for ($i = 0; $i < strlen($hex); $i+=8) {
                $bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT);
            }
            return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
        }
    
        /**
         * Converts a BigInteger to a base-10 number.
         *
         * Here's an example:
         * 
         * toString(); // outputs 50
         * ?>
         * 
         *
         * @return String
         * @access public
         * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
         */
        function toString()
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    return gmp_strval($this->value);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    if ($this->value === '0') {
                        return '0';
                    }
    
                    return ltrim($this->value, '0');
            }
    
            if (!count($this->value)) {
                return '0';
            }
    
            $temp = $this->copy();
            $temp->is_negative = false;
    
            $divisor = new Math_BigInteger();
            $divisor->value = array(10000000); // eg. 10**7
            $result = '';
            while (count($temp->value)) {
                list($temp, $mod) = $temp->divide($divisor);
                $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result;
            }
            $result = ltrim($result, '0');
            if (empty($result)) {
                $result = '0';
            }
    
            if ($this->is_negative) {
                $result = '-' . $result;
            }
    
            return $result;
        }
    
        /**
         * Copy an object
         *
         * PHP5 passes objects by reference while PHP4 passes by value.  As such, we need a function to guarantee
         * that all objects are passed by value, when appropriate.  More information can be found here:
         *
         * {@link http://php.net/language.oop5.basic#51624}
         *
         * @access public
         * @see __clone()
         * @return Math_BigInteger
         */
        function copy()
        {
            $temp = new Math_BigInteger();
            $temp->value = $this->value;
            $temp->is_negative = $this->is_negative;
            $temp->generator = $this->generator;
            $temp->precision = $this->precision;
            $temp->bitmask = $this->bitmask;
            return $temp;
        }
    
        /**
         *  __toString() magic method
         *
         * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
         * toString().
         *
         * @access public
         * @internal Implemented per a suggestion by Techie-Michael - thanks!
         */
        function __toString()
        {
            return $this->toString();
        }
    
        /**
         * __clone() magic method
         *
         * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
         * directly in PHP5.  You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
         * only syntax of $y = clone $x.  As such, if you're trying to write an application that works on both PHP4 and PHP5,
         * call Math_BigInteger::copy(), instead.
         *
         * @access public
         * @see copy()
         * @return Math_BigInteger
         */
        function __clone()
        {
            return $this->copy();
        }
    
        /**
         *  __sleep() magic method
         *
         * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
         *
         * @see __wakeup()
         * @access public
         */
        function __sleep()
        {
            $this->hex = $this->toHex(true);
            $vars = array('hex');
            if ($this->generator != 'mt_rand') {
                $vars[] = 'generator';
            }
            if ($this->precision > 0) {
                $vars[] = 'precision';
            }
            return $vars;
            
        }
    
        /**
         *  __wakeup() magic method
         *
         * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
         *
         * @see __sleep()
         * @access public
         */
        function __wakeup()
        {
            $temp = new Math_BigInteger($this->hex, -16);
            $this->value = $temp->value;
            $this->is_negative = $temp->is_negative;
            $this->setRandomGenerator($this->generator);
            if ($this->precision > 0) {
                // recalculate $this->bitmask
                $this->setPrecision($this->precision);
            }
        }
    
        /**
         * Adds two BigIntegers.
         *
         * Here's an example:
         * 
         * add($b);
         *
         *    echo $c->toString(); // outputs 30
         * ?>
         * 
         *
         * @param Math_BigInteger $y
         * @return Math_BigInteger
         * @access public
         * @internal Performs base-2**52 addition
         */
        function add($y)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp = new Math_BigInteger();
                    $temp->value = gmp_add($this->value, $y->value);
    
                    return $this->_normalize($temp);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $temp = new Math_BigInteger();
                    $temp->value = bcadd($this->value, $y->value, 0);
    
                    return $this->_normalize($temp);
            }
    
            $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
    
            $result = new Math_BigInteger();
            $result->value = $temp[MATH_BIGINTEGER_VALUE];
            $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
    
            return $this->_normalize($result);
        }
    
        /**
         * Performs addition.
         *
         * @param Array $x_value
         * @param Boolean $x_negative
         * @param Array $y_value
         * @param Boolean $y_negative
         * @return Array
         * @access private
         */
        function _add($x_value, $x_negative, $y_value, $y_negative)
        {
            $x_size = count($x_value);
            $y_size = count($y_value);
    
            if ($x_size == 0) {
                return array(
                    MATH_BIGINTEGER_VALUE => $y_value,
                    MATH_BIGINTEGER_SIGN => $y_negative
                );
            } else if ($y_size == 0) {
                return array(
                    MATH_BIGINTEGER_VALUE => $x_value,
                    MATH_BIGINTEGER_SIGN => $x_negative
                );
            }
    
            // subtract, if appropriate
            if ( $x_negative != $y_negative ) {
                if ( $x_value == $y_value ) {
                    return array(
                        MATH_BIGINTEGER_VALUE => array(),
                        MATH_BIGINTEGER_SIGN => false
                    );
                }
    
                $temp = $this->_subtract($x_value, false, $y_value, false);
                $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
                                              $x_negative : $y_negative;
    
                return $temp;
            }
    
            if ($x_size < $y_size) {
                $size = $x_size;
                $value = $y_value;
            } else {
                $size = $y_size;
                $value = $x_value;
            }
    
            $value[] = 0; // just in case the carry adds an extra digit
    
            $carry = 0;
            for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
                $sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry;
                $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
                $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
    
                $temp = (int) ($sum / 0x4000000);
    
                $value[$i] = (int) ($sum - 0x4000000 * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
                $value[$j] = $temp;
            }
    
            if ($j == $size) { // ie. if $y_size is odd
                $sum = $x_value[$i] + $y_value[$i] + $carry;
                $carry = $sum >= 0x4000000;
                $value[$i] = $carry ? $sum - 0x4000000 : $sum;
                ++$i; // ie. let $i = $j since we've just done $value[$i]
            }
    
            if ($carry) {
                for (; $value[$i] == 0x3FFFFFF; ++$i) {
                    $value[$i] = 0;
                }
                ++$value[$i];
            }
    
            return array(
                MATH_BIGINTEGER_VALUE => $this->_trim($value),
                MATH_BIGINTEGER_SIGN => $x_negative
            );
        }
    
        /**
         * Subtracts two BigIntegers.
         *
         * Here's an example:
         * 
         * subtract($b);
         *
         *    echo $c->toString(); // outputs -10
         * ?>
         * 
         *
         * @param Math_BigInteger $y
         * @return Math_BigInteger
         * @access public
         * @internal Performs base-2**52 subtraction
         */
        function subtract($y)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp = new Math_BigInteger();
                    $temp->value = gmp_sub($this->value, $y->value);
    
                    return $this->_normalize($temp);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $temp = new Math_BigInteger();
                    $temp->value = bcsub($this->value, $y->value, 0);
    
                    return $this->_normalize($temp);
            }
    
            $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
    
            $result = new Math_BigInteger();
            $result->value = $temp[MATH_BIGINTEGER_VALUE];
            $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
    
            return $this->_normalize($result);
        }
    
        /**
         * Performs subtraction.
         *
         * @param Array $x_value
         * @param Boolean $x_negative
         * @param Array $y_value
         * @param Boolean $y_negative
         * @return Array
         * @access private
         */
        function _subtract($x_value, $x_negative, $y_value, $y_negative)
        {
            $x_size = count($x_value);
            $y_size = count($y_value);
    
            if ($x_size == 0) {
                return array(
                    MATH_BIGINTEGER_VALUE => $y_value,
                    MATH_BIGINTEGER_SIGN => !$y_negative
                );
            } else if ($y_size == 0) {
                return array(
                    MATH_BIGINTEGER_VALUE => $x_value,
                    MATH_BIGINTEGER_SIGN => $x_negative
                );
            }
    
            // add, if appropriate (ie. -$x - +$y or +$x - -$y)
            if ( $x_negative != $y_negative ) {
                $temp = $this->_add($x_value, false, $y_value, false);
                $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
    
                return $temp;
            }
    
            $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
    
            if ( !$diff ) {
                return array(
                    MATH_BIGINTEGER_VALUE => array(),
                    MATH_BIGINTEGER_SIGN => false
                );
            }
    
            // switch $x and $y around, if appropriate.
            if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
                $temp = $x_value;
                $x_value = $y_value;
                $y_value = $temp;
    
                $x_negative = !$x_negative;
    
                $x_size = count($x_value);
                $y_size = count($y_value);
            }
    
            // at this point, $x_value should be at least as big as - if not bigger than - $y_value
    
            $carry = 0;
            for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
                $sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry;
                $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
                $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
    
                $temp = (int) ($sum / 0x4000000);
    
                $x_value[$i] = (int) ($sum - 0x4000000 * $temp);
                $x_value[$j] = $temp;
            }
    
            if ($j == $y_size) { // ie. if $y_size is odd
                $sum = $x_value[$i] - $y_value[$i] - $carry;
                $carry = $sum < 0;
                $x_value[$i] = $carry ? $sum + 0x4000000 : $sum;
                ++$i;
            }
    
            if ($carry) {
                for (; !$x_value[$i]; ++$i) {
                    $x_value[$i] = 0x3FFFFFF;
                }
                --$x_value[$i];
            }
    
            return array(
                MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
                MATH_BIGINTEGER_SIGN => $x_negative
            );
        }
    
        /**
         * Multiplies two BigIntegers
         *
         * Here's an example:
         * 
         * multiply($b);
         *
         *    echo $c->toString(); // outputs 200
         * ?>
         * 
         *
         * @param Math_BigInteger $x
         * @return Math_BigInteger
         * @access public
         */
        function multiply($x)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp = new Math_BigInteger();
                    $temp->value = gmp_mul($this->value, $x->value);
    
                    return $this->_normalize($temp);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $temp = new Math_BigInteger();
                    $temp->value = bcmul($this->value, $x->value, 0);
    
                    return $this->_normalize($temp);
            }
    
            $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
    
            $product = new Math_BigInteger();
            $product->value = $temp[MATH_BIGINTEGER_VALUE];
            $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
    
            return $this->_normalize($product);
        }
    
        /**
         * Performs multiplication.
         *
         * @param Array $x_value
         * @param Boolean $x_negative
         * @param Array $y_value
         * @param Boolean $y_negative
         * @return Array
         * @access private
         */
        function _multiply($x_value, $x_negative, $y_value, $y_negative)
        {
            //if ( $x_value == $y_value ) {
            //    return array(
            //        MATH_BIGINTEGER_VALUE => $this->_square($x_value),
            //        MATH_BIGINTEGER_SIGN => $x_sign != $y_value
            //    );
            //}
    
            $x_length = count($x_value);
            $y_length = count($y_value);
    
            if ( !$x_length || !$y_length ) { // a 0 is being multiplied
                return array(
                    MATH_BIGINTEGER_VALUE => array(),
                    MATH_BIGINTEGER_SIGN => false
                );
            }
    
            return array(
                MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
                    $this->_trim($this->_regularMultiply($x_value, $y_value)) :
                    $this->_trim($this->_karatsuba($x_value, $y_value)),
                MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
            );
        }
    
        /**
         * Performs long multiplication on two BigIntegers
         *
         * Modeled after 'multiply' in MutableBigInteger.java.
         *
         * @param Array $x_value
         * @param Array $y_value
         * @return Array
         * @access private
         */
        function _regularMultiply($x_value, $y_value)
        {
            $x_length = count($x_value);
            $y_length = count($y_value);
    
            if ( !$x_length || !$y_length ) { // a 0 is being multiplied
                return array();
            }
    
            if ( $x_length < $y_length ) {
                $temp = $x_value;
                $x_value = $y_value;
                $y_value = $temp;
    
                $x_length = count($x_value);
                $y_length = count($y_value);
            }
    
            $product_value = $this->_array_repeat(0, $x_length + $y_length);
    
            // the following for loop could be removed if the for loop following it
            // (the one with nested for loops) initially set $i to 0, but
            // doing so would also make the result in one set of unnecessary adds,
            // since on the outermost loops first pass, $product->value[$k] is going
            // to always be 0
    
            $carry = 0;
    
            for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
                $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
                $carry = (int) ($temp / 0x4000000);
                $product_value[$j] = (int) ($temp - 0x4000000 * $carry);
            }
    
            $product_value[$j] = $carry;
    
            // the above for loop is what the previous comment was talking about.  the
            // following for loop is the "one with nested for loops"
            for ($i = 1; $i < $y_length; ++$i) {
                $carry = 0;
    
                for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
                    $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
                    $carry = (int) ($temp / 0x4000000);
                    $product_value[$k] = (int) ($temp - 0x4000000 * $carry);
                }
    
                $product_value[$k] = $carry;
            }
    
            return $product_value;
        }
    
        /**
         * Performs Karatsuba multiplication on two BigIntegers
         *
         * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
         * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
         *
         * @param Array $x_value
         * @param Array $y_value
         * @return Array
         * @access private
         */
        function _karatsuba($x_value, $y_value)
        {
            $m = min(count($x_value) >> 1, count($y_value) >> 1);
    
            if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
                return $this->_regularMultiply($x_value, $y_value);
            }
    
            $x1 = array_slice($x_value, $m);
            $x0 = array_slice($x_value, 0, $m);
            $y1 = array_slice($y_value, $m);
            $y0 = array_slice($y_value, 0, $m);
    
            $z2 = $this->_karatsuba($x1, $y1);
            $z0 = $this->_karatsuba($x0, $y0);
    
            $z1 = $this->_add($x1, false, $x0, false);
            $temp = $this->_add($y1, false, $y0, false);
            $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
            $temp = $this->_add($z2, false, $z0, false);
            $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
    
            $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
            $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
    
            $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
            $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
    
            return $xy[MATH_BIGINTEGER_VALUE];
        }
    
        /**
         * Performs squaring
         *
         * @param Array $x
         * @return Array
         * @access private
         */
        function _square($x = false)
        {
            return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
                $this->_trim($this->_baseSquare($x)) :
                $this->_trim($this->_karatsubaSquare($x));
        }
    
        /**
         * Performs traditional squaring on two BigIntegers
         *
         * Squaring can be done faster than multiplying a number by itself can be.  See
         * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
         * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
         *
         * @param Array $value
         * @return Array
         * @access private
         */
        function _baseSquare($value)
        {
            if ( empty($value) ) {
                return array();
            }
            $square_value = $this->_array_repeat(0, 2 * count($value));
    
            for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
                $i2 = $i << 1;
    
                $temp = $square_value[$i2] + $value[$i] * $value[$i];
                $carry = (int) ($temp / 0x4000000);
                $square_value[$i2] = (int) ($temp - 0x4000000 * $carry);
    
                // note how we start from $i+1 instead of 0 as we do in multiplication.
                for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
                    $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
                    $carry = (int) ($temp / 0x4000000);
                    $square_value[$k] = (int) ($temp - 0x4000000 * $carry);
                }
    
                // the following line can yield values larger 2**15.  at this point, PHP should switch
                // over to floats.
                $square_value[$i + $max_index + 1] = $carry;
            }
    
            return $square_value;
        }
    
        /**
         * Performs Karatsuba "squaring" on two BigIntegers
         *
         * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
         * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
         *
         * @param Array $value
         * @return Array
         * @access private
         */
        function _karatsubaSquare($value)
        {
            $m = count($value) >> 1;
    
            if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
                return $this->_baseSquare($value);
            }
    
            $x1 = array_slice($value, $m);
            $x0 = array_slice($value, 0, $m);
    
            $z2 = $this->_karatsubaSquare($x1);
            $z0 = $this->_karatsubaSquare($x0);
    
            $z1 = $this->_add($x1, false, $x0, false);
            $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
            $temp = $this->_add($z2, false, $z0, false);
            $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
    
            $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
            $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
    
            $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
            $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
    
            return $xx[MATH_BIGINTEGER_VALUE];
        }
    
        /**
         * Divides two BigIntegers.
         *
         * Returns an array whose first element contains the quotient and whose second element contains the
         * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
         * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
         * and the divisor (basically, the "common residue" is the first positive modulo).
         *
         * Here's an example:
         * 
         * divide($b);
         *
         *    echo $quotient->toString(); // outputs 0
         *    echo "\r\n";
         *    echo $remainder->toString(); // outputs 10
         * ?>
         * 
         *
         * @param Math_BigInteger $y
         * @return Array
         * @access public
         * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
         */
        function divide($y)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $quotient = new Math_BigInteger();
                    $remainder = new Math_BigInteger();
    
                    list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
    
                    if (gmp_sign($remainder->value) < 0) {
                        $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
                    }
    
                    return array($this->_normalize($quotient), $this->_normalize($remainder));
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $quotient = new Math_BigInteger();
                    $remainder = new Math_BigInteger();
    
                    $quotient->value = bcdiv($this->value, $y->value, 0);
                    $remainder->value = bcmod($this->value, $y->value);
    
                    if ($remainder->value[0] == '-') {
                        $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
                    }
    
                    return array($this->_normalize($quotient), $this->_normalize($remainder));
            }
    
            if (count($y->value) == 1) {
                list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
                $quotient = new Math_BigInteger();
                $remainder = new Math_BigInteger();
                $quotient->value = $q;
                $remainder->value = array($r);
                $quotient->is_negative = $this->is_negative != $y->is_negative;
                return array($this->_normalize($quotient), $this->_normalize($remainder));
            }
    
            static $zero;
            if ( !isset($zero) ) {
                $zero = new Math_BigInteger();
            }
    
            $x = $this->copy();
            $y = $y->copy();
    
            $x_sign = $x->is_negative;
            $y_sign = $y->is_negative;
    
            $x->is_negative = $y->is_negative = false;
    
            $diff = $x->compare($y);
    
            if ( !$diff ) {
                $temp = new Math_BigInteger();
                $temp->value = array(1);
                $temp->is_negative = $x_sign != $y_sign;
                return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
            }
    
            if ( $diff < 0 ) {
                // if $x is negative, "add" $y.
                if ( $x_sign ) {
                    $x = $y->subtract($x);
                }
                return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
            }
    
            // normalize $x and $y as described in HAC 14.23 / 14.24
            $msb = $y->value[count($y->value) - 1];
            for ($shift = 0; !($msb & 0x2000000); ++$shift) {
                $msb <<= 1;
            }
            $x->_lshift($shift);
            $y->_lshift($shift);
            $y_value = &$y->value;
    
            $x_max = count($x->value) - 1;
            $y_max = count($y->value) - 1;
    
            $quotient = new Math_BigInteger();
            $quotient_value = &$quotient->value;
            $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
    
            static $temp, $lhs, $rhs;
            if (!isset($temp)) {
                $temp = new Math_BigInteger();
                $lhs =  new Math_BigInteger();
                $rhs =  new Math_BigInteger();
            }
            $temp_value = &$temp->value;
            $rhs_value =  &$rhs->value;
    
            // $temp = $y << ($x_max - $y_max-1) in base 2**26
            $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
    
            while ( $x->compare($temp) >= 0 ) {
                // calculate the "common residue"
                ++$quotient_value[$x_max - $y_max];
                $x = $x->subtract($temp);
                $x_max = count($x->value) - 1;
            }
    
            for ($i = $x_max; $i >= $y_max + 1; --$i) {
                $x_value = &$x->value;
                $x_window = array(
                    isset($x_value[$i]) ? $x_value[$i] : 0,
                    isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
                    isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
                );
                $y_window = array(
                    $y_value[$y_max],
                    ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
                );
    
                $q_index = $i - $y_max - 1;
                if ($x_window[0] == $y_window[0]) {
                    $quotient_value[$q_index] = 0x3FFFFFF;
                } else {
                    $quotient_value[$q_index] = (int) (
                        ($x_window[0] * 0x4000000 + $x_window[1])
                        /
                        $y_window[0]
                    );
                }
    
                $temp_value = array($y_window[1], $y_window[0]);
    
                $lhs->value = array($quotient_value[$q_index]);
                $lhs = $lhs->multiply($temp);
    
                $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
    
                while ( $lhs->compare($rhs) > 0 ) {
                    --$quotient_value[$q_index];
    
                    $lhs->value = array($quotient_value[$q_index]);
                    $lhs = $lhs->multiply($temp);
                }
    
                $adjust = $this->_array_repeat(0, $q_index);
                $temp_value = array($quotient_value[$q_index]);
                $temp = $temp->multiply($y);
                $temp_value = &$temp->value;
                $temp_value = array_merge($adjust, $temp_value);
    
                $x = $x->subtract($temp);
    
                if ($x->compare($zero) < 0) {
                    $temp_value = array_merge($adjust, $y_value);
                    $x = $x->add($temp);
    
                    --$quotient_value[$q_index];
                }
    
                $x_max = count($x_value) - 1;
            }
    
            // unnormalize the remainder
            $x->_rshift($shift);
    
            $quotient->is_negative = $x_sign != $y_sign;
    
            // calculate the "common residue", if appropriate
            if ( $x_sign ) {
                $y->_rshift($shift);
                $x = $y->subtract($x);
            }
    
            return array($this->_normalize($quotient), $this->_normalize($x));
        }
    
        /**
         * Divides a BigInteger by a regular integer
         *
         * abc / x = a00 / x + b0 / x + c / x
         *
         * @param Array $dividend
         * @param Array $divisor
         * @return Array
         * @access private
         */
        function _divide_digit($dividend, $divisor)
        {
            $carry = 0;
            $result = array();
    
            for ($i = count($dividend) - 1; $i >= 0; --$i) {
                $temp = 0x4000000 * $carry + $dividend[$i];
                $result[$i] = (int) ($temp / $divisor);
                $carry = (int) ($temp - $divisor * $result[$i]);
            }
    
            return array($result, $carry);
        }
    
        /**
         * Performs modular exponentiation.
         *
         * Here's an example:
         * 
         * modPow($b, $c);
         *
         *    echo $c->toString(); // outputs 10
         * ?>
         * 
         *
         * @param Math_BigInteger $e
         * @param Math_BigInteger $n
         * @return Math_BigInteger
         * @access public
         * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
         *    and although the approach involving repeated squaring does vastly better, it, too, is impractical
         *    for our purposes.  The reason being that division - by far the most complicated and time-consuming
         *    of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
         *
         *    Modular reductions resolve this issue.  Although an individual modular reduction takes more time
         *    then an individual division, when performed in succession (with the same modulo), they're a lot faster.
         *
         *    The two most commonly used modular reductions are Barrett and Montgomery reduction.  Montgomery reduction,
         *    although faster, only works when the gcd of the modulo and of the base being used is 1.  In RSA, when the
         *    base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
         *    the product of two odd numbers is odd), but what about when RSA isn't used?
         *
         *    In contrast, Barrett reduction has no such constraint.  As such, some bigint implementations perform a
         *    Barrett reduction after every operation in the modpow function.  Others perform Barrett reductions when the
         *    modulo is even and Montgomery reductions when the modulo is odd.  BigInteger.java's modPow method, however,
         *    uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
         *    the other, a power of two - and recombine them, later.  This is the method that this modPow function uses.
         *    {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
         */
        function modPow($e, $n)
        {
            $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
    
            if ($e->compare(new Math_BigInteger()) < 0) {
                $e = $e->abs();
    
                $temp = $this->modInverse($n);
                if ($temp === false) {
                    return false;
                }
    
                return $this->_normalize($temp->modPow($e, $n));
            }
    
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp = new Math_BigInteger();
                    $temp->value = gmp_powm($this->value, $e->value, $n->value);
    
                    return $this->_normalize($temp);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $temp = new Math_BigInteger();
                    $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
    
                    return $this->_normalize($temp);
            }
    
            if ( empty($e->value) ) {
                $temp = new Math_BigInteger();
                $temp->value = array(1);
                return $this->_normalize($temp);
            }
    
            if ( $e->value == array(1) ) {
                list(, $temp) = $this->divide($n);
                return $this->_normalize($temp);
            }
    
            if ( $e->value == array(2) ) {
                $temp = new Math_BigInteger();
                $temp->value = $this->_square($this->value);
                list(, $temp) = $temp->divide($n);
                return $this->_normalize($temp);
            }
    
            return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
    
            // is the modulo odd?
            if ( $n->value[0] & 1 ) {
                return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
            }
            // if it's not, it's even
    
            // find the lowest set bit (eg. the max pow of 2 that divides $n)
            for ($i = 0; $i < count($n->value); ++$i) {
                if ( $n->value[$i] ) {
                    $temp = decbin($n->value[$i]);
                    $j = strlen($temp) - strrpos($temp, '1') - 1;
                    $j+= 26 * $i;
                    break;
                }
            }
            // at this point, 2^$j * $n/(2^$j) == $n
    
            $mod1 = $n->copy();
            $mod1->_rshift($j);
            $mod2 = new Math_BigInteger();
            $mod2->value = array(1);
            $mod2->_lshift($j);
    
            $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
            $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
    
            $y1 = $mod2->modInverse($mod1);
            $y2 = $mod1->modInverse($mod2);
    
            $result = $part1->multiply($mod2);
            $result = $result->multiply($y1);
    
            $temp = $part2->multiply($mod1);
            $temp = $temp->multiply($y2);
    
            $result = $result->add($temp);
            list(, $result) = $result->divide($n);
    
            return $this->_normalize($result);
        }
    
        /**
         * Performs modular exponentiation.
         *
         * Alias for Math_BigInteger::modPow()
         *
         * @param Math_BigInteger $e
         * @param Math_BigInteger $n
         * @return Math_BigInteger
         * @access public
         */
        function powMod($e, $n)
        {
            return $this->modPow($e, $n);
        }
    
        /**
         * Sliding Window k-ary Modular Exponentiation
         *
         * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
         * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}.  In a departure from those algorithims,
         * however, this function performs a modular reduction after every multiplication and squaring operation.
         * As such, this function has the same preconditions that the reductions being used do.
         *
         * @param Math_BigInteger $e
         * @param Math_BigInteger $n
         * @param Integer $mode
         * @return Math_BigInteger
         * @access private
         */
        function _slidingWindow($e, $n, $mode)
        {
            static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
            //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
    
            $e_value = $e->value;
            $e_length = count($e_value) - 1;
            $e_bits = decbin($e_value[$e_length]);
            for ($i = $e_length - 1; $i >= 0; --$i) {
                $e_bits.= str_pad(decbin($e_value[$i]), 26, '0', STR_PAD_LEFT);
            }
    
            $e_length = strlen($e_bits);
    
            // calculate the appropriate window size.
            // $window_size == 3 if $window_ranges is between 25 and 81, for example.
            for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
    
            $n_value = $n->value;
    
            // precompute $this^0 through $this^$window_size
            $powers = array();
            $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
            $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
    
            // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
            // in a 1.  ie. it's supposed to be odd.
            $temp = 1 << ($window_size - 1);
            for ($i = 1; $i < $temp; ++$i) {
                $i2 = $i << 1;
                $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
            }
    
            $result = array(1);
            $result = $this->_prepareReduce($result, $n_value, $mode);
    
            for ($i = 0; $i < $e_length; ) {
                if ( !$e_bits[$i] ) {
                    $result = $this->_squareReduce($result, $n_value, $mode);
                    ++$i;
                } else {
                    for ($j = $window_size - 1; $j > 0; --$j) {
                        if ( !empty($e_bits[$i + $j]) ) {
                            break;
                        }
                    }
    
                    for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
                        $result = $this->_squareReduce($result, $n_value, $mode);
                    }
    
                    $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
    
                    $i+=$j + 1;
                }
            }
    
            $temp = new Math_BigInteger();
            $temp->value = $this->_reduce($result, $n_value, $mode);
    
            return $temp;
        }
    
        /**
         * Modular reduction
         *
         * For most $modes this will return the remainder.
         *
         * @see _slidingWindow()
         * @access private
         * @param Array $x
         * @param Array $n
         * @param Integer $mode
         * @return Array
         */
        function _reduce($x, $n, $mode)
        {
            switch ($mode) {
                case MATH_BIGINTEGER_MONTGOMERY:
                    return $this->_montgomery($x, $n);
                case MATH_BIGINTEGER_BARRETT:
                    return $this->_barrett($x, $n);
                case MATH_BIGINTEGER_POWEROF2:
                    $lhs = new Math_BigInteger();
                    $lhs->value = $x;
                    $rhs = new Math_BigInteger();
                    $rhs->value = $n;
                    return $x->_mod2($n);
                case MATH_BIGINTEGER_CLASSIC:
                    $lhs = new Math_BigInteger();
                    $lhs->value = $x;
                    $rhs = new Math_BigInteger();
                    $rhs->value = $n;
                    list(, $temp) = $lhs->divide($rhs);
                    return $temp->value;
                case MATH_BIGINTEGER_NONE:
                    return $x;
                default:
                    // an invalid $mode was provided
            }
        }
    
        /**
         * Modular reduction preperation
         *
         * @see _slidingWindow()
         * @access private
         * @param Array $x
         * @param Array $n
         * @param Integer $mode
         * @return Array
         */
        function _prepareReduce($x, $n, $mode)
        {
            if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
                return $this->_prepMontgomery($x, $n);
            }
            return $this->_reduce($x, $n, $mode);
        }
    
        /**
         * Modular multiply
         *
         * @see _slidingWindow()
         * @access private
         * @param Array $x
         * @param Array $y
         * @param Array $n
         * @param Integer $mode
         * @return Array
         */
        function _multiplyReduce($x, $y, $n, $mode)
        {
            if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
                return $this->_montgomeryMultiply($x, $y, $n);
            }
            $temp = $this->_multiply($x, false, $y, false);
            return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
        }
    
        /**
         * Modular square
         *
         * @see _slidingWindow()
         * @access private
         * @param Array $x
         * @param Array $n
         * @param Integer $mode
         * @return Array
         */
        function _squareReduce($x, $n, $mode)
        {
            if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
                return $this->_montgomeryMultiply($x, $x, $n);
            }
            return $this->_reduce($this->_square($x), $n, $mode);
        }
    
        /**
         * Modulos for Powers of Two
         *
         * Calculates $x%$n, where $n = 2**$e, for some $e.  Since this is basically the same as doing $x & ($n-1),
         * we'll just use this function as a wrapper for doing that.
         *
         * @see _slidingWindow()
         * @access private
         * @param Math_BigInteger
         * @return Math_BigInteger
         */
        function _mod2($n)
        {
            $temp = new Math_BigInteger();
            $temp->value = array(1);
            return $this->bitwise_and($n->subtract($temp));
        }
    
        /**
         * Barrett Modular Reduction
         *
         * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
         * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information.  Modified slightly,
         * so as not to require negative numbers (initially, this script didn't support negative numbers).
         *
         * Employs "folding", as described at
         * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}.  To quote from
         * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
         *
         * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
         * usable on account of (1) its not using reasonable radix points as discussed in
         * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
         * radix points, it only works when there are an even number of digits in the denominator.  The reason for (2) is that
         * (x >> 1) + (x >> 1) != x / 2 + x / 2.  If x is even, they're the same, but if x is odd, they're not.  See the in-line
         * comments for details.
         *
         * @see _slidingWindow()
         * @access private
         * @param Array $n
         * @param Array $m
         * @return Array
         */
        function _barrett($n, $m)
        {
            static $cache = array(
                MATH_BIGINTEGER_VARIABLE => array(),
                MATH_BIGINTEGER_DATA => array()
            );
    
            $m_length = count($m);
    
            // if ($this->_compare($n, $this->_square($m)) >= 0) {
            if (count($n) > 2 * $m_length) {
                $lhs = new Math_BigInteger();
                $rhs = new Math_BigInteger();
                $lhs->value = $n;
                $rhs->value = $m;
                list(, $temp) = $lhs->divide($rhs);
                return $temp->value;
            }
    
            // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
            if ($m_length < 5) {
                return $this->_regularBarrett($n, $m);
            }
    
            // n = 2 * m.length
    
            if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
                $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
                $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
    
                $lhs = new Math_BigInteger();
                $lhs_value = &$lhs->value;
                $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
                $lhs_value[] = 1;
                $rhs = new Math_BigInteger();
                $rhs->value = $m;
    
                list($u, $m1) = $lhs->divide($rhs);
                $u = $u->value;
                $m1 = $m1->value;
    
                $cache[MATH_BIGINTEGER_DATA][] = array(
                    'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
                    'm1'=> $m1 // m.length
                );
            } else {
                extract($cache[MATH_BIGINTEGER_DATA][$key]);
            }
    
            $cutoff = $m_length + ($m_length >> 1);
            $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
            $msd = array_slice($n, $cutoff);    // m.length >> 1
            $lsd = $this->_trim($lsd);
            $temp = $this->_multiply($msd, false, $m1, false);
            $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
    
            if ($m_length & 1) {
                return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
            }
    
            // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
            $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
            // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
            // if odd:  ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
            $temp = $this->_multiply($temp, false, $u, false);
            // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
            // if odd:  (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
            $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
            // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
            // if odd:  (m.length - (m.length >> 1)) + m.length     = 2 * m.length - (m.length >> 1)
            $temp = $this->_multiply($temp, false, $m, false);
    
            // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
            // number from a m.length + (m.length >> 1) + 1 digit number.  ie. there'd be an extra digit and the while loop
            // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
    
            $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
    
            while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
                $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
            }
    
            return $result[MATH_BIGINTEGER_VALUE];
        }
    
        /**
         * (Regular) Barrett Modular Reduction
         *
         * For numbers with more than four digits Math_BigInteger::_barrett() is faster.  The difference between that and this
         * is that this function does not fold the denominator into a smaller form.
         *
         * @see _slidingWindow()
         * @access private
         * @param Array $x
         * @param Array $n
         * @return Array
         */
        function _regularBarrett($x, $n)
        {
            static $cache = array(
                MATH_BIGINTEGER_VARIABLE => array(),
                MATH_BIGINTEGER_DATA => array()
            );
    
            $n_length = count($n);
    
            if (count($x) > 2 * $n_length) {
                $lhs = new Math_BigInteger();
                $rhs = new Math_BigInteger();
                $lhs->value = $x;
                $rhs->value = $n;
                list(, $temp) = $lhs->divide($rhs);
                return $temp->value;
            }
    
            if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
                $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
                $cache[MATH_BIGINTEGER_VARIABLE][] = $n;
                $lhs = new Math_BigInteger();
                $lhs_value = &$lhs->value;
                $lhs_value = $this->_array_repeat(0, 2 * $n_length);
                $lhs_value[] = 1;
                $rhs = new Math_BigInteger();
                $rhs->value = $n;
                list($temp, ) = $lhs->divide($rhs); // m.length
                $cache[MATH_BIGINTEGER_DATA][] = $temp->value;
            }
    
            // 2 * m.length - (m.length - 1) = m.length + 1
            $temp = array_slice($x, $n_length - 1);
            // (m.length + 1) + m.length = 2 * m.length + 1
            $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
            // (2 * m.length + 1) - (m.length - 1) = m.length + 2
            $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
    
            // m.length + 1
            $result = array_slice($x, 0, $n_length + 1);
            // m.length + 1
            $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
            // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
    
            if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
                $corrector_value = $this->_array_repeat(0, $n_length + 1);
                $corrector_value[] = 1;
                $result = $this->_add($result, false, $corrector, false);
                $result = $result[MATH_BIGINTEGER_VALUE];
            }
    
            // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
            $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
            while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
                $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
            }
    
            return $result[MATH_BIGINTEGER_VALUE];
        }
    
        /**
         * Performs long multiplication up to $stop digits
         *
         * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
         *
         * @see _regularBarrett()
         * @param Array $x_value
         * @param Boolean $x_negative
         * @param Array $y_value
         * @param Boolean $y_negative
         * @return Array
         * @access private
         */
        function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
        {
            $x_length = count($x_value);
            $y_length = count($y_value);
    
            if ( !$x_length || !$y_length ) { // a 0 is being multiplied
                return array(
                    MATH_BIGINTEGER_VALUE => array(),
                    MATH_BIGINTEGER_SIGN => false
                );
            }
    
            if ( $x_length < $y_length ) {
                $temp = $x_value;
                $x_value = $y_value;
                $y_value = $temp;
    
                $x_length = count($x_value);
                $y_length = count($y_value);
            }
    
            $product_value = $this->_array_repeat(0, $x_length + $y_length);
    
            // the following for loop could be removed if the for loop following it
            // (the one with nested for loops) initially set $i to 0, but
            // doing so would also make the result in one set of unnecessary adds,
            // since on the outermost loops first pass, $product->value[$k] is going
            // to always be 0
    
            $carry = 0;
    
            for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
                $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
                $carry = (int) ($temp / 0x4000000);
                $product_value[$j] = (int) ($temp - 0x4000000 * $carry);
            }
    
            if ($j < $stop) {
                $product_value[$j] = $carry;
            }
    
            // the above for loop is what the previous comment was talking about.  the
            // following for loop is the "one with nested for loops"
    
            for ($i = 1; $i < $y_length; ++$i) {
                $carry = 0;
    
                for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
                    $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
                    $carry = (int) ($temp / 0x4000000);
                    $product_value[$k] = (int) ($temp - 0x4000000 * $carry);
                }
    
                if ($k < $stop) {
                    $product_value[$k] = $carry;
                }
            }
    
            return array(
                MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
                MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
            );
        }
    
        /**
         * Montgomery Modular Reduction
         *
         * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
         * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
         * improved upon (basically, by using the comba method).  gcd($n, 2) must be equal to one for this function
         * to work correctly.
         *
         * @see _prepMontgomery()
         * @see _slidingWindow()
         * @access private
         * @param Array $x
         * @param Array $n
         * @return Array
         */
        function _montgomery($x, $n)
        {
            static $cache = array(
                MATH_BIGINTEGER_VARIABLE => array(),
                MATH_BIGINTEGER_DATA => array()
            );
    
            if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
                $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
                $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
                $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
            }
    
            $k = count($n);
    
            $result = array(MATH_BIGINTEGER_VALUE => $x);
    
            for ($i = 0; $i < $k; ++$i) {
                $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
                $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
                $temp = $this->_regularMultiply(array($temp), $n);
                $temp = array_merge($this->_array_repeat(0, $i), $temp);
                $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
            }
    
            $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
    
            if ($this->_compare($result, false, $n, false) >= 0) {
                $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
            }
    
            return $result[MATH_BIGINTEGER_VALUE];
        }
    
        /**
         * Montgomery Multiply
         *
         * Interleaves the montgomery reduction and long multiplication algorithms together as described in 
         * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
         *
         * @see _prepMontgomery()
         * @see _montgomery()
         * @access private
         * @param Array $x
         * @param Array $y
         * @param Array $m
         * @return Array
         */
        function _montgomeryMultiply($x, $y, $m)
        {
            $temp = $this->_multiply($x, false, $y, false);
            return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
    
            static $cache = array(
                MATH_BIGINTEGER_VARIABLE => array(),
                MATH_BIGINTEGER_DATA => array()
            );
    
            if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
                $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
                $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
                $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
            }
    
            $n = max(count($x), count($y), count($m));
            $x = array_pad($x, $n, 0);
            $y = array_pad($y, $n, 0);
            $m = array_pad($m, $n, 0);
            $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
            for ($i = 0; $i < $n; ++$i) {
                $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
                $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
                $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
                $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
                $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
                $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
                $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
            }
            if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
                $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
            }
            return $a[MATH_BIGINTEGER_VALUE];
        }
    
        /**
         * Prepare a number for use in Montgomery Modular Reductions
         *
         * @see _montgomery()
         * @see _slidingWindow()
         * @access private
         * @param Array $x
         * @param Array $n
         * @return Array
         */
        function _prepMontgomery($x, $n)
        {
            $lhs = new Math_BigInteger();
            $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
            $rhs = new Math_BigInteger();
            $rhs->value = $n;
    
            list(, $temp) = $lhs->divide($rhs);
            return $temp->value;
        }
    
        /**
         * Modular Inverse of a number mod 2**26 (eg. 67108864)
         *
         * Based off of the bnpInvDigit function implemented and justified in the following URL:
         *
         * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
         *
         * The following URL provides more info:
         *
         * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
         *
         * As for why we do all the bitmasking...  strange things can happen when converting from floats to ints. For
         * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields 
         * int(-2147483648).  To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
         * auto-converted to floats.  The outermost bitmask is present because without it, there's no guarantee that
         * the "residue" returned would be the so-called "common residue".  We use fmod, in the last step, because the
         * maximum possible $x is 26 bits and the maximum $result is 16 bits.  Thus, we have to be able to handle up to
         * 40 bits, which only 64-bit floating points will support.
         *
         * Thanks to Pedro Gimeno Fortea for input!
         *
         * @see _montgomery()
         * @access private
         * @param Array $x
         * @return Integer
         */
        function _modInverse67108864($x) // 2**26 == 67108864
        {
            $x = -$x[0];
            $result = $x & 0x3; // x**-1 mod 2**2
            $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
            $result = ($result * (2 - ($x & 0xFF) * $result))  & 0xFF; // x**-1 mod 2**8
            $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
            $result = fmod($result * (2 - fmod($x * $result, 0x4000000)), 0x4000000); // x**-1 mod 2**26
            return $result & 0x3FFFFFF;
        }
    
        /**
         * Calculates modular inverses.
         *
         * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
         *
         * Here's an example:
         * 
         * modInverse($b);
         *    echo $c->toString(); // outputs 4
         *
         *    echo "\r\n";
         *
         *    $d = $a->multiply($c);
         *    list(, $d) = $d->divide($b);
         *    echo $d; // outputs 1 (as per the definition of modular inverse)
         * ?>
         * 
         *
         * @param Math_BigInteger $n
         * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.
         * @access public
         * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
         */
        function modInverse($n)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp = new Math_BigInteger();
                    $temp->value = gmp_invert($this->value, $n->value);
    
                    return ( $temp->value === false ) ? false : $this->_normalize($temp);
            }
    
            static $zero, $one;
            if (!isset($zero)) {
                $zero = new Math_BigInteger();
                $one = new Math_BigInteger(1);
            }
    
            // $x mod $n == $x mod -$n.
            $n = $n->abs();
    
            if ($this->compare($zero) < 0) {
                $temp = $this->abs();
                $temp = $temp->modInverse($n);
                return $negated === false ? false : $this->_normalize($n->subtract($temp));
            }
    
            extract($this->extendedGCD($n));
    
            if (!$gcd->equals($one)) {
                return false;
            }
    
            $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
    
            return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
        }
    
        /**
         * Calculates the greatest common divisor and Bézout's identity.
         *
         * Say you have 693 and 609.  The GCD is 21.  Bézout's identity states that there exist integers x and y such that
         * 693*x + 609*y == 21.  In point of fact, there are actually an infinite number of x and y combinations and which
         * combination is returned is dependant upon which mode is in use.  See
         * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bézout's identity - Wikipedia} for more information.
         *
         * Here's an example:
         * 
         * extendedGCD($b));
         *
         *    echo $gcd->toString() . "\r\n"; // outputs 21
         *    echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
         * ?>
         * 
         *
         * @param Math_BigInteger $n
         * @return Math_BigInteger
         * @access public
         * @internal Calculates the GCD using the binary xGCD algorithim described in
         *    {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}.  As the text above 14.61 notes,
         *    the more traditional algorithim requires "relatively costly multiple-precision divisions".
         */
        function extendedGCD($n)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    extract(gmp_gcdext($this->value, $n->value));
    
                    return array(
                        'gcd' => $this->_normalize(new Math_BigInteger($g)),
                        'x'   => $this->_normalize(new Math_BigInteger($s)),
                        'y'   => $this->_normalize(new Math_BigInteger($t))
                    );
                case MATH_BIGINTEGER_MODE_BCMATH:
                    // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
                    // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway.  as is,
                    // the basic extended euclidean algorithim is what we're using.
    
                    $u = $this->value;
                    $v = $n->value;
    
                    $a = '1';
                    $b = '0';
                    $c = '0';
                    $d = '1';
    
                    while (bccomp($v, '0', 0) != 0) {
                        $q = bcdiv($u, $v, 0);
    
                        $temp = $u;
                        $u = $v;
                        $v = bcsub($temp, bcmul($v, $q, 0), 0);
    
                        $temp = $a;
                        $a = $c;
                        $c = bcsub($temp, bcmul($a, $q, 0), 0);
    
                        $temp = $b;
                        $b = $d;
                        $d = bcsub($temp, bcmul($b, $q, 0), 0);
                    }
    
                    return array(
                        'gcd' => $this->_normalize(new Math_BigInteger($u)),
                        'x'   => $this->_normalize(new Math_BigInteger($a)),
                        'y'   => $this->_normalize(new Math_BigInteger($b))
                    );
            }
    
            $y = $n->copy();
            $x = $this->copy();
            $g = new Math_BigInteger();
            $g->value = array(1);
    
            while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
                $x->_rshift(1);
                $y->_rshift(1);
                $g->_lshift(1);
            }
    
            $u = $x->copy();
            $v = $y->copy();
    
            $a = new Math_BigInteger();
            $b = new Math_BigInteger();
            $c = new Math_BigInteger();
            $d = new Math_BigInteger();
    
            $a->value = $d->value = $g->value = array(1);
            $b->value = $c->value = array();
    
            while ( !empty($u->value) ) {
                while ( !($u->value[0] & 1) ) {
                    $u->_rshift(1);
                    if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {
                        $a = $a->add($y);
                        $b = $b->subtract($x);
                    }
                    $a->_rshift(1);
                    $b->_rshift(1);
                }
    
                while ( !($v->value[0] & 1) ) {
                    $v->_rshift(1);
                    if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {
                        $c = $c->add($y);
                        $d = $d->subtract($x);
                    }
                    $c->_rshift(1);
                    $d->_rshift(1);
                }
    
                if ($u->compare($v) >= 0) {
                    $u = $u->subtract($v);
                    $a = $a->subtract($c);
                    $b = $b->subtract($d);
                } else {
                    $v = $v->subtract($u);
                    $c = $c->subtract($a);
                    $d = $d->subtract($b);
                }
            }
    
            return array(
                'gcd' => $this->_normalize($g->multiply($v)),
                'x'   => $this->_normalize($c),
                'y'   => $this->_normalize($d)
            );
        }
    
        /**
         * Calculates the greatest common divisor
         *
         * Say you have 693 and 609.  The GCD is 21.
         *
         * Here's an example:
         * 
         * extendedGCD($b);
         *
         *    echo $gcd->toString() . "\r\n"; // outputs 21
         * ?>
         * 
         *
         * @param Math_BigInteger $n
         * @return Math_BigInteger
         * @access public
         */
        function gcd($n)
        {
            extract($this->extendedGCD($n));
            return $gcd;
        }
    
        /**
         * Absolute value.
         *
         * @return Math_BigInteger
         * @access public
         */
        function abs()
        {
            $temp = new Math_BigInteger();
    
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp->value = gmp_abs($this->value);
                    break;
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
                    break;
                default:
                    $temp->value = $this->value;
            }
    
            return $temp;
        }
    
        /**
         * Compares two numbers.
         *
         * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this is
         * demonstrated thusly:
         *
         * $x  > $y: $x->compare($y)  > 0
         * $x  < $y: $x->compare($y)  < 0
         * $x == $y: $x->compare($y) == 0
         *
         * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
         *
         * @param Math_BigInteger $x
         * @return Integer < 0 if $this is less than $x; > 0 if $this is greater than $x, and 0 if they are equal.
         * @access public
         * @see equals()
         * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
         */
        function compare($y)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    return gmp_cmp($this->value, $y->value);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    return bccomp($this->value, $y->value, 0);
            }
    
            return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
        }
    
        /**
         * Compares two numbers.
         *
         * @param Array $x_value
         * @param Boolean $x_negative
         * @param Array $y_value
         * @param Boolean $y_negative
         * @return Integer
         * @see compare()
         * @access private
         */
        function _compare($x_value, $x_negative, $y_value, $y_negative)
        {
            if ( $x_negative != $y_negative ) {
                return ( !$x_negative && $y_negative ) ? 1 : -1;
            }
    
            $result = $x_negative ? -1 : 1;
    
            if ( count($x_value) != count($y_value) ) {
                return ( count($x_value) > count($y_value) ) ? $result : -$result;
            }
            $size = max(count($x_value), count($y_value));
    
            $x_value = array_pad($x_value, $size, 0);
            $y_value = array_pad($y_value, $size, 0);
    
            for ($i = count($x_value) - 1; $i >= 0; --$i) {
                if ($x_value[$i] != $y_value[$i]) {
                    return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
                }
            }
    
            return 0;
        }
    
        /**
         * Tests the equality of two numbers.
         *
         * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
         *
         * @param Math_BigInteger $x
         * @return Boolean
         * @access public
         * @see compare()
         */
        function equals($x)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    return gmp_cmp($this->value, $x->value) == 0;
                default:
                    return $this->value === $x->value && $this->is_negative == $x->is_negative;
            }
        }
    
        /**
         * Set Precision
         *
         * Some bitwise operations give different results depending on the precision being used.  Examples include left
         * shift, not, and rotates.
         *
         * @param Math_BigInteger $x
         * @access public
         * @return Math_BigInteger
         */
        function setPrecision($bits)
        {
            $this->precision = $bits;
            if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
                $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
            } else {
                $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
            }
    
            $temp = $this->_normalize($this);
            $this->value = $temp->value;
        }
    
        /**
         * Logical And
         *
         * @param Math_BigInteger $x
         * @access public
         * @internal Implemented per a request by Lluis Pamies i Juarez 
         * @return Math_BigInteger
         */
        function bitwise_and($x)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp = new Math_BigInteger();
                    $temp->value = gmp_and($this->value, $x->value);
    
                    return $this->_normalize($temp);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $left = $this->toBytes();
                    $right = $x->toBytes();
    
                    $length = max(strlen($left), strlen($right));
    
                    $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
                    $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
    
                    return $this->_normalize(new Math_BigInteger($left & $right, 256));
            }
    
            $result = $this->copy();
    
            $length = min(count($x->value), count($this->value));
    
            $result->value = array_slice($result->value, 0, $length);
    
            for ($i = 0; $i < $length; ++$i) {
                $result->value[$i] = $result->value[$i] & $x->value[$i];
            }
    
            return $this->_normalize($result);
        }
    
        /**
         * Logical Or
         *
         * @param Math_BigInteger $x
         * @access public
         * @internal Implemented per a request by Lluis Pamies i Juarez 
         * @return Math_BigInteger
         */
        function bitwise_or($x)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp = new Math_BigInteger();
                    $temp->value = gmp_or($this->value, $x->value);
    
                    return $this->_normalize($temp);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $left = $this->toBytes();
                    $right = $x->toBytes();
    
                    $length = max(strlen($left), strlen($right));
    
                    $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
                    $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
    
                    return $this->_normalize(new Math_BigInteger($left | $right, 256));
            }
    
            $length = max(count($this->value), count($x->value));
            $result = $this->copy();
            $result->value = array_pad($result->value, 0, $length);
            $x->value = array_pad($x->value, 0, $length);
    
            for ($i = 0; $i < $length; ++$i) {
                $result->value[$i] = $this->value[$i] | $x->value[$i];
            }
    
            return $this->_normalize($result);
        }
    
        /**
         * Logical Exclusive-Or
         *
         * @param Math_BigInteger $x
         * @access public
         * @internal Implemented per a request by Lluis Pamies i Juarez 
         * @return Math_BigInteger
         */
        function bitwise_xor($x)
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    $temp = new Math_BigInteger();
                    $temp->value = gmp_xor($this->value, $x->value);
    
                    return $this->_normalize($temp);
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $left = $this->toBytes();
                    $right = $x->toBytes();
    
                    $length = max(strlen($left), strlen($right));
    
                    $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
                    $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
    
                    return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
            }
    
            $length = max(count($this->value), count($x->value));
            $result = $this->copy();
            $result->value = array_pad($result->value, 0, $length);
            $x->value = array_pad($x->value, 0, $length);
    
            for ($i = 0; $i < $length; ++$i) {
                $result->value[$i] = $this->value[$i] ^ $x->value[$i];
            }
    
            return $this->_normalize($result);
        }
    
        /**
         * Logical Not
         *
         * @access public
         * @internal Implemented per a request by Lluis Pamies i Juarez 
         * @return Math_BigInteger
         */
        function bitwise_not()
        {
            // calculuate "not" without regard to $this->precision
            // (will always result in a smaller number.  ie. ~1 isn't 1111 1110 - it's 0)
            $temp = $this->toBytes();
            $pre_msb = decbin(ord($temp[0]));
            $temp = ~$temp;
            $msb = decbin(ord($temp[0]));
            if (strlen($msb) == 8) {
                $msb = substr($msb, strpos($msb, '0'));
            }
            $temp[0] = chr(bindec($msb));
    
            // see if we need to add extra leading 1's
            $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
            $new_bits = $this->precision - $current_bits;
            if ($new_bits <= 0) {
                return $this->_normalize(new Math_BigInteger($temp, 256));
            }
    
            // generate as many leading 1's as we need to.
            $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
            $this->_base256_lshift($leading_ones, $current_bits);
    
            $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT);
    
            return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
        }
    
        /**
         * Logical Right Shift
         *
         * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
         *
         * @param Integer $shift
         * @return Math_BigInteger
         * @access public
         * @internal The only version that yields any speed increases is the internal version.
         */
        function bitwise_rightShift($shift)
        {
            $temp = new Math_BigInteger();
    
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    static $two;
    
                    if (!isset($two)) {
                        $two = gmp_init('2');
                    }
    
                    $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
    
                    break;
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
    
                    break;
                default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
                         // and I don't want to do that...
                    $temp->value = $this->value;
                    $temp->_rshift($shift);
            }
    
            return $this->_normalize($temp);
        }
    
        /**
         * Logical Left Shift
         *
         * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
         *
         * @param Integer $shift
         * @return Math_BigInteger
         * @access public
         * @internal The only version that yields any speed increases is the internal version.
         */
        function bitwise_leftShift($shift)
        {
            $temp = new Math_BigInteger();
    
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    static $two;
    
                    if (!isset($two)) {
                        $two = gmp_init('2');
                    }
    
                    $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
    
                    break;
                case MATH_BIGINTEGER_MODE_BCMATH:
                    $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
    
                    break;
                default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
                         // and I don't want to do that...
                    $temp->value = $this->value;
                    $temp->_lshift($shift);
            }
    
            return $this->_normalize($temp);
        }
    
        /**
         * Logical Left Rotate
         *
         * Instead of the top x bits being dropped they're appended to the shifted bit string.
         *
         * @param Integer $shift
         * @return Math_BigInteger
         * @access public
         */
        function bitwise_leftRotate($shift)
        {
            $bits = $this->toBytes();
    
            if ($this->precision > 0) {
                $precision = $this->precision;
                if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
                    $mask = $this->bitmask->subtract(new Math_BigInteger(1));
                    $mask = $mask->toBytes();
                } else {
                    $mask = $this->bitmask->toBytes();
                }
            } else {
                $temp = ord($bits[0]);
                for ($i = 0; $temp >> $i; ++$i);
                $precision = 8 * strlen($bits) - 8 + $i;
                $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
            }
    
            if ($shift < 0) {
                $shift+= $precision;
            }
            $shift%= $precision;
    
            if (!$shift) {
                return $this->copy();
            }
    
            $left = $this->bitwise_leftShift($shift);
            $left = $left->bitwise_and(new Math_BigInteger($mask, 256));
            $right = $this->bitwise_rightShift($precision - $shift);
            $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
            return $this->_normalize($result);
        }
    
        /**
         * Logical Right Rotate
         *
         * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
         *
         * @param Integer $shift
         * @return Math_BigInteger
         * @access public
         */
        function bitwise_rightRotate($shift)
        {
            return $this->bitwise_leftRotate(-$shift);
        }
    
        /**
         * Set random number generator function
         *
         * $generator should be the name of a random generating function whose first parameter is the minimum
         * value and whose second parameter is the maximum value.  If this function needs to be seeded, it should
         * be seeded prior to calling Math_BigInteger::random() or Math_BigInteger::randomPrime()
         *
         * If the random generating function is not explicitly set, it'll be assumed to be mt_rand().
         *
         * @see random()
         * @see randomPrime()
         * @param optional String $generator
         * @access public
         */
        function setRandomGenerator($generator)
        {
            $this->generator = $generator;
        }
    
        /**
         * Generate a random number
         *
         * @param optional Integer $min
         * @param optional Integer $max
         * @return Math_BigInteger
         * @access public
         */
        function random($min = false, $max = false)
        {
            if ($min === false) {
                $min = new Math_BigInteger(0);
            }
    
            if ($max === false) {
                $max = new Math_BigInteger(0x7FFFFFFF);
            }
    
            $compare = $max->compare($min);
    
            if (!$compare) {
                return $this->_normalize($min);
            } else if ($compare < 0) {
                // if $min is bigger then $max, swap $min and $max
                $temp = $max;
                $max = $min;
                $min = $temp;
            }
    
            $generator = $this->generator;
    
            $max = $max->subtract($min);
            $max = ltrim($max->toBytes(), chr(0));
            $size = strlen($max) - 1;
            $random = '';
    
            $bytes = $size & 1;
            for ($i = 0; $i < $bytes; ++$i) {
                $random.= chr($generator(0, 255));
            }
    
            $blocks = $size >> 1;
            for ($i = 0; $i < $blocks; ++$i) {
                // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
                $random.= pack('n', $generator(0, 0xFFFF));
            }
    
            $temp = new Math_BigInteger($random, 256);
            if ($temp->compare(new Math_BigInteger(substr($max, 1), 256)) > 0) {
                $random = chr($generator(0, ord($max[0]) - 1)) . $random;
            } else {
                $random = chr($generator(0, ord($max[0])    )) . $random;
            }
    
            $random = new Math_BigInteger($random, 256);
    
            return $this->_normalize($random->add($min));
        }
    
        /**
         * Generate a random prime number.
         *
         * If there's not a prime within the given range, false will be returned.  If more than $timeout seconds have elapsed,
         * give up and return false.
         *
         * @param optional Integer $min
         * @param optional Integer $max
         * @param optional Integer $timeout
         * @return Math_BigInteger
         * @access public
         * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
         */
        function randomPrime($min = false, $max = false, $timeout = false)
        {
            $compare = $max->compare($min);
    
            if (!$compare) {
                return $min;
            } else if ($compare < 0) {
                // if $min is bigger then $max, swap $min and $max
                $temp = $max;
                $max = $min;
                $min = $temp;
            }
    
            // gmp_nextprime() requires PHP 5 >= 5.2.0 per .
            if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
                // we don't rely on Math_BigInteger::random()'s min / max when gmp_nextprime() is being used since this function
                // does its own checks on $max / $min when gmp_nextprime() is used.  When gmp_nextprime() is not used, however,
                // the same $max / $min checks are not performed.
                if ($min === false) {
                    $min = new Math_BigInteger(0);
                }
    
                if ($max === false) {
                    $max = new Math_BigInteger(0x7FFFFFFF);
                }
    
                $x = $this->random($min, $max);
    
                $x->value = gmp_nextprime($x->value);
    
                if ($x->compare($max) <= 0) {
                    return $x;
                }
    
                $x->value = gmp_nextprime($min->value);
    
                if ($x->compare($max) <= 0) {
                    return $x;
                }
    
                return false;
            }
    
            static $one, $two;
            if (!isset($one)) {
                $one = new Math_BigInteger(1);
                $two = new Math_BigInteger(2);
            }
    
            $start = time();
    
            $x = $this->random($min, $max);
            if ($x->equals($two)) {
                return $x;
            }
    
            $x->_make_odd();
            if ($x->compare($max) > 0) {
                // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
                if ($min->equals($max)) {
                    return false;
                }
                $x = $min->copy();
                $x->_make_odd();
            }
    
            $initial_x = $x->copy();
    
            while (true) {
                if ($timeout !== false && time() - $start > $timeout) {
                    return false;
                }
    
                if ($x->isPrime()) {
                    return $x;
                }
    
                $x = $x->add($two);
    
                if ($x->compare($max) > 0) {
                    $x = $min->copy();
                    if ($x->equals($two)) {
                        return $x;
                    }
                    $x->_make_odd();
                }
    
                if ($x->equals($initial_x)) {
                    return false;
                }
            }
        }
    
        /**
         * Make the current number odd
         *
         * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.
         *
         * @see randomPrime()
         * @access private
         */
        function _make_odd()
        {
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    gmp_setbit($this->value, 0);
                    break;
                case MATH_BIGINTEGER_MODE_BCMATH:
                    if ($this->value[strlen($this->value) - 1] % 2 == 0) {
                        $this->value = bcadd($this->value, '1');
                    }
                    break;
                default:
                    $this->value[0] |= 1;
            }
        }
    
        /**
         * Checks a numer to see if it's prime
         *
         * Assuming the $t parameter is not set, this function has an error rate of 2**-80.  The main motivation for the
         * $t parameter is distributability.  Math_BigInteger::randomPrime() can be distributed accross multiple pageloads
         * on a website instead of just one.
         *
         * @param optional Integer $t
         * @return Boolean
         * @access public
         * @internal Uses the
         *     {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}.  See 
         *     {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
         */
        function isPrime($t = false)
        {
            $length = strlen($this->toBytes());
    
            if (!$t) {
                // see HAC 4.49 "Note (controlling the error probability)"
                     if ($length >= 163) { $t =  2; } // floor(1300 / 8)
                else if ($length >= 106) { $t =  3; } // floor( 850 / 8)
                else if ($length >= 81 ) { $t =  4; } // floor( 650 / 8)
                else if ($length >= 68 ) { $t =  5; } // floor( 550 / 8)
                else if ($length >= 56 ) { $t =  6; } // floor( 450 / 8)
                else if ($length >= 50 ) { $t =  7; } // floor( 400 / 8)
                else if ($length >= 43 ) { $t =  8; } // floor( 350 / 8)
                else if ($length >= 37 ) { $t =  9; } // floor( 300 / 8)
                else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
                else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
                else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
                else                     { $t = 27; }
            }
    
            // ie. gmp_testbit($this, 0)
            // ie. isEven() or !isOdd()
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    return gmp_prob_prime($this->value, $t) != 0;
                case MATH_BIGINTEGER_MODE_BCMATH:
                    if ($this->value === '2') {
                        return true;
                    }
                    if ($this->value[strlen($this->value) - 1] % 2 == 0) {
                        return false;
                    }
                    break;
                default:
                    if ($this->value == array(2)) {
                        return true;
                    }
                    if (~$this->value[0] & 1) {
                        return false;
                    }
            }
    
            static $primes, $zero, $one, $two;
    
            if (!isset($primes)) {
                $primes = array(
                    3,    5,    7,    11,   13,   17,   19,   23,   29,   31,   37,   41,   43,   47,   53,   59,   
                    61,   67,   71,   73,   79,   83,   89,   97,   101,  103,  107,  109,  113,  127,  131,  137,  
                    139,  149,  151,  157,  163,  167,  173,  179,  181,  191,  193,  197,  199,  211,  223,  227,  
                    229,  233,  239,  241,  251,  257,  263,  269,  271,  277,  281,  283,  293,  307,  311,  313,  
                    317,  331,  337,  347,  349,  353,  359,  367,  373,  379,  383,  389,  397,  401,  409,  419,  
                    421,  431,  433,  439,  443,  449,  457,  461,  463,  467,  479,  487,  491,  499,  503,  509,  
                    521,  523,  541,  547,  557,  563,  569,  571,  577,  587,  593,  599,  601,  607,  613,  617,  
                    619,  631,  641,  643,  647,  653,  659,  661,  673,  677,  683,  691,  701,  709,  719,  727,  
                    733,  739,  743,  751,  757,  761,  769,  773,  787,  797,  809,  811,  821,  823,  827,  829,  
                    839,  853,  857,  859,  863,  877,  881,  883,  887,  907,  911,  919,  929,  937,  941,  947,  
                    953,  967,  971,  977,  983,  991,  997
                );
    
                if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
                    for ($i = 0; $i < count($primes); ++$i) {
                        $primes[$i] = new Math_BigInteger($primes[$i]);
                    }
                }
    
                $zero = new Math_BigInteger();
                $one = new Math_BigInteger(1);
                $two = new Math_BigInteger(2);
            }
    
            if ($this->equals($one)) {
                return false;
            }
    
            // see HAC 4.4.1 "Random search for probable primes"
            if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
                foreach ($primes as $prime) {
                    list(, $r) = $this->divide($prime);
                    if ($r->equals($zero)) {
                        return $this->equals($prime);
                    }
                }
            } else {
                $value = $this->value;
                foreach ($primes as $prime) {
                    list(, $r) = $this->_divide_digit($value, $prime);
                    if (!$r) {
                        return count($value) == 1 && $value[0] == $prime;
                    }
                }
            }
    
            $n   = $this->copy();
            $n_1 = $n->subtract($one);
            $n_2 = $n->subtract($two);
    
            $r = $n_1->copy();
            $r_value = $r->value;
            // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
            if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
                $s = 0;
                // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
                while ($r->value[strlen($r->value) - 1] % 2 == 0) {
                    $r->value = bcdiv($r->value, '2', 0);
                    ++$s;
                }
            } else {
                for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
                    $temp = ~$r_value[$i] & 0xFFFFFF;
                    for ($j = 1; ($temp >> $j) & 1; ++$j);
                    if ($j != 25) {
                        break;
                    }
                }
                $s = 26 * $i + $j - 1;
                $r->_rshift($s);
            }
    
            for ($i = 0; $i < $t; ++$i) {
                $a = $this->random($two, $n_2);
                $y = $a->modPow($r, $n);
    
                if (!$y->equals($one) && !$y->equals($n_1)) {
                    for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
                        $y = $y->modPow($two, $n);
                        if ($y->equals($one)) {
                            return false;
                        }
                    }
    
                    if (!$y->equals($n_1)) {
                        return false;
                    }
                }
            }
            return true;
        }
    
        /**
         * Logical Left Shift
         *
         * Shifts BigInteger's by $shift bits.
         *
         * @param Integer $shift
         * @access private
         */
        function _lshift($shift)
        {
            if ( $shift == 0 ) {
                return;
            }
    
            $num_digits = (int) ($shift / 26);
            $shift %= 26;
            $shift = 1 << $shift;
    
            $carry = 0;
    
            for ($i = 0; $i < count($this->value); ++$i) {
                $temp = $this->value[$i] * $shift + $carry;
                $carry = (int) ($temp / 0x4000000);
                $this->value[$i] = (int) ($temp - $carry * 0x4000000);
            }
    
            if ( $carry ) {
                $this->value[] = $carry;
            }
    
            while ($num_digits--) {
                array_unshift($this->value, 0);
            }
        }
    
        /**
         * Logical Right Shift
         *
         * Shifts BigInteger's by $shift bits.
         *
         * @param Integer $shift
         * @access private
         */
        function _rshift($shift)
        {
            if ($shift == 0) {
                return;
            }
    
            $num_digits = (int) ($shift / 26);
            $shift %= 26;
            $carry_shift = 26 - $shift;
            $carry_mask = (1 << $shift) - 1;
    
            if ( $num_digits ) {
                $this->value = array_slice($this->value, $num_digits);
            }
    
            $carry = 0;
    
            for ($i = count($this->value) - 1; $i >= 0; --$i) {
                $temp = $this->value[$i] >> $shift | $carry;
                $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
                $this->value[$i] = $temp;
            }
    
            $this->value = $this->_trim($this->value);
        }
    
        /**
         * Normalize
         *
         * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
         *
         * @param Math_BigInteger
         * @return Math_BigInteger
         * @see _trim()
         * @access private
         */
        function _normalize($result)
        {
            $result->precision = $this->precision;
            $result->bitmask = $this->bitmask;
    
            switch ( MATH_BIGINTEGER_MODE ) {
                case MATH_BIGINTEGER_MODE_GMP:
                    if (!empty($result->bitmask->value)) {
                        $result->value = gmp_and($result->value, $result->bitmask->value);
                    }
    
                    return $result;
                case MATH_BIGINTEGER_MODE_BCMATH:
                    if (!empty($result->bitmask->value)) {
                        $result->value = bcmod($result->value, $result->bitmask->value);
                    }
    
                    return $result;
            }
    
            $value = &$result->value;
    
            if ( !count($value) ) {
                return $result;
            }
    
            $value = $this->_trim($value);
    
            if (!empty($result->bitmask->value)) {
                $length = min(count($value), count($this->bitmask->value));
                $value = array_slice($value, 0, $length);
    
                for ($i = 0; $i < $length; ++$i) {
                    $value[$i] = $value[$i] & $this->bitmask->value[$i];
                }
            }
    
            return $result;
        }
    
        /**
         * Trim
         *
         * Removes leading zeros
         *
         * @return Math_BigInteger
         * @access private
         */
        function _trim($value)
        {
            for ($i = count($value) - 1; $i >= 0; --$i) {
                if ( $value[$i] ) {
                    break;
                }
                unset($value[$i]);
            }
    
            return $value;
        }
    
        /**
         * Array Repeat
         *
         * @param $input Array
         * @param $multiplier mixed
         * @return Array
         * @access private
         */
        function _array_repeat($input, $multiplier)
        {
            return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
        }
    
        /**
         * Logical Left Shift
         *
         * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
         *
         * @param $x String
         * @param $shift Integer
         * @return String
         * @access private
         */
        function _base256_lshift(&$x, $shift)
        {
            if ($shift == 0) {
                return;
            }
    
            $num_bytes = $shift >> 3; // eg. floor($shift/8)
            $shift &= 7; // eg. $shift % 8
    
            $carry = 0;
            for ($i = strlen($x) - 1; $i >= 0; --$i) {
                $temp = ord($x[$i]) << $shift | $carry;
                $x[$i] = chr($temp);
                $carry = $temp >> 8;
            }
            $carry = ($carry != 0) ? chr($carry) : '';
            $x = $carry . $x . str_repeat(chr(0), $num_bytes);
        }
    
        /**
         * Logical Right Shift
         *
         * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
         *
         * @param $x String
         * @param $shift Integer
         * @return String
         * @access private
         */
        function _base256_rshift(&$x, $shift)
        {
            if ($shift == 0) {
                $x = ltrim($x, chr(0));
                return '';
            }
    
            $num_bytes = $shift >> 3; // eg. floor($shift/8)
            $shift &= 7; // eg. $shift % 8
    
            $remainder = '';
            if ($num_bytes) {
                $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
                $remainder = substr($x, $start);
                $x = substr($x, 0, -$num_bytes);
            }
    
            $carry = 0;
            $carry_shift = 8 - $shift;
            for ($i = 0; $i < strlen($x); ++$i) {
                $temp = (ord($x[$i]) >> $shift) | $carry;
                $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
                $x[$i] = chr($temp);
            }
            $x = ltrim($x, chr(0));
    
            $remainder = chr($carry >> $carry_shift) . $remainder;
    
            return ltrim($remainder, chr(0));
        }
    
        // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
        // at 32-bits, while java's longs are 64-bits.
    
        /**
         * Converts 32-bit integers to bytes.
         *
         * @param Integer $x
         * @return String
         * @access private
         */
        function _int2bytes($x)
        {
            return ltrim(pack('N', $x), chr(0));
        }
    
        /**
         * Converts bytes to 32-bit integers
         *
         * @param String $x
         * @return Integer
         * @access private
         */
        function _bytes2int($x)
        {
            $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
            return $temp['int'];
        }
    }debian/db-update/v20111210/lib/0000755000000000000000000000000012267045571012667 5ustar  debian/db-update/v20111210/lib/SpotTiming.php0000644000000000000000000000261112267045571015475 0ustar   microtime(true));
    	} # start
    	
    	static function stop($name, $extra = '') {
    		if (self::$_disabled) return;
    
    		self::$_inflight[$name]['stop'] = microtime(true);
    		self::$_inflight[$name]['extra'] = $extra;
    		self::$_inflight[$name]['level'] = self::$_curlevel;
    		self::$_curlevel--;
    
    		self::$_timings[] = array_merge(self::$_inflight[$name], array('name' => $name));
    		unset(self::$_inflight[$name]);
    	} # stop
    	
    	static function display() {
    		if (self::$_disabled) return;
    		
    		echo '';
    		
    		foreach(array_reverse(self::$_timings) as $values) {
    			echo '' . PHP_EOL;
    		} # foreach
    	
    		echo '
    NameTimeExtra
    ' . str_pad('', $values['level'], '.') . $values['name'] . '' . ($values['stop'] - $values['start']) . '' . serialize($values['extra']) . '




    '; } # display() } # class SpotTimingdebian/db-update/v20111210/lib/SpotSecurity.php0000644000000000000000000001371012267045571016057 0ustar "Display overview of spots", 1 => "Log in", 2 => "Perform a search", 3 => "View spot in detail", 4 => "Retrieve NZB file", 5 => "Download manager integration", 6 => "Mark spots as read", 7 => "View image of spot", 8 => "RSS feed", 9 => "Static resources", 10 => "Create new user", 11 => "Change own preferences", 12 => "Change own user settings", 13 => "List all users", 14 => "Post comments to a spot", 15 => "Log out", 16 => "Use downloads manager API ", 17 => "Keep watchlist", 18 => "Keep downloadlist", 19 => "Keep seenlist", 20 => "Show new spotcount in list of filters", 21 => "Display Retrieve new spots button", 22 => "Display comments of a spot", 23 => "Let user choose their template", 24 => "Use Spotweb using an API key", 25 => "Change other users", 26 => "Display total amount of spots", 27 => "Delete users", 28 => "Change users' group membeship", 29 => "Display users' group membership", 30 => "Change security groups", 31 => "Send notifications (per service)", 32 => "Send notifications (per type)", 33 => "Let users create their own CSS", 34 => "Create own Spot filters", 35 => "Set a set of filters as default for new users", 36 => "Report a spot as spam", 37 => "Post a new spot", 38 => "Blacklist a spotter", 39 => "Display statistics", 40 => "Display Spotweb's changelog", 41 => "Change settings" ); /* * Audit levels */ const spot_secaudit_none = 0; const spot_secaudit_failure = 1; const spot_secaudit_all = 2; function __construct(SpotDb $db, SpotSettings $settings, array $user, $ipaddr) { $this->_db = $db; $this->_user = $user; $this->_settings = $settings; $this->_failAudit = ($settings->get('auditlevel') == SpotSecurity::spot_secaudit_failure); $this->_allAudit = ($settings->get('auditlevel') == SpotSecurity::spot_secaudit_all); if (($this->_failAudit) || ($this->_allAudit)) { $this->_spotAudit = new SpotAudit($db, $settings, $user, $ipaddr); } # if $this->_permissions = $db->getPermissions($user['userid']); } # ctor function allowed($perm, $object) { $allowed = isset($this->_permissions[$perm][$object]) && $this->_permissions[$perm][$object]; # We check for auditing in SpotSecurity to prevent the overhead # of a function call for each security check if (($this->_allAudit) || ((!$allowed) && ($this->_failAudit))) { $this->_spotAudit->audit($perm, $object, $allowed); } # if return $allowed; } # allowed function fatalPermCheck($perm, $object) { if (!$this->allowed($perm, $object)) { throw new PermissionDeniedException($perm, $object); } # if } # fatalPermCheck function toHuman($perm) { return $this->_secHumanReadable[$perm]; } # toHuman function getAllPermissions() { return $this->_secHumanReadable; } # getAllPermissions function securityValid() { # SPOTWEB_SECURITY_VERSION is gedefinieerd bovenin dit bestand return ($this->_settings->get('securityversion') == SPOTWEB_SECURITY_VERSION); } # securityValid } # class SpotSecurity debian/db-update/v20111210/lib/notifications/0000755000000000000000000000000012267045571015540 5ustar debian/db-update/v20111210/lib/notifications/Notifications_Factory.php0000644000000000000000000000223512267045571022553 0ustar _db = $db; $this->_settings = $settings; } # ctor function update() { $this->createSecurityGroups(); $this->createAnonymous(); $this->createAdmin(); $this->updateUserPreferences(); $this->updateSecurityGroupMembership(); $this->updateUserFilters(); # Fix for a bug introduced by me (3nov2011) if ($this->_settings->get('securityversion') === 'true') { # Reinsert the users' membership of groups $dbCon = $this->_db->getDbHandle(); $dbCon->rawExec("INSERT INTO usergroups(userid, groupid, prio) VALUES(1, 1, 1)"); $dbCon->rawExec("INSERT INTO usergroups(userid,groupid,prio) VALUES(2, 1, 1)"); $dbCon->rawExec("INSERT INTO usergroups(userid,groupid,prio) VALUES(2, 2, 2)"); $dbCon->rawExec("INSERT INTO usergroups(userid,groupid,prio) VALUES(2, 3, 3)"); # now for all users, readd them to the default 'authenticated users' membership $userList = $this->_db->listUsers("", 0, 9999999); foreach($userList['list'] as $user) { if ($user['userid'] > 2) { $dbCon->rawExec("INSERT INTO usergroups(userid,groupid,prio) VALUES(" . $user['userid'] . ", 1, 1)"); $dbCon->rawExec("INSERT INTO usergroups(userid,groupid,prio) VALUES(" . $user['userid'] . ", 2, 2)"); } # if } # foreach } # if $this->updateSecurityVersion(); } # update() /* * Creates the anonymous user */ function createAnonymous() { # if we already have an anonymous user, exit $anonUser = $this->_db->getUser(1); if ($anonUser !== false) { if ($anonUser['username'] != 'anonymous') { throw new Exception("Anonymous user is not anonymous anymore. Database logical corrupted, unable to continue"); } # if return ; } # if # DB connectie $dbCon = $this->_db->getDbHandle(); # Maak een apikey aan. Deze kan niet worden gebruikt, maar is bij voorkeur niet leeg $apikey = md5('anonymous'); # Create the dummy 'anonymous' user $anonymous_user = array( # 'userid' => 1, <= Moet 1 zijn voor de anonymous user 'username' => 'anonymous', 'firstname' => 'Jane', 'passhash' => '', 'lastname' => 'Doe', 'mail' => 'john@example.com', 'apikey' => $apikey, 'lastlogin' => 0, 'lastvisit' => 0, 'deleted' => 0); $this->_db->addUser($anonymous_user); # update handmatig het userid $currentId = $dbCon->singleQuery("SELECT id FROM users WHERE username = 'anonymous'"); $dbCon->exec("UPDATE users SET id = 1 WHERE username = 'anonymous'"); $dbCon->exec("UPDATE usersettings SET userid = 1 WHERE userid = '%s'", Array( (int) $currentId)); # Geef de anonieme user de anonymous group $dbCon->rawExec("INSERT INTO usergroups(userid, groupid, prio) VALUES(1, 1, 1)"); } # createAnonymous /* * Create the admin user */ function createAdmin() { # if we already have an admin user, exit $adminUser = $this->_db->getUser(2); if ($adminUser !== false) { return ; } # if # DB connectie $dbCon = $this->_db->getDbHandle(); # Vraag de password salt op $passSalt = $this->_settings->get('pass_salt'); # Bereken het password van de dummy admin user $adminPwdHash = sha1(strrev(substr($passSalt, 1, 3)) . 'admin' . $passSalt); # Maak een apikey aan. Deze kan niet worden gebruikt, maar is bij voorkeur niet leeg $apikey = md5('admin'); # Create the dummy 'admin' user $admin_user = array( # 'userid' => 2, 'username' => 'admin', 'firstname' => 'admin', 'passhash' => $adminPwdHash, 'lastname' => 'user', 'mail' => 'spotwebadmin@example.com', 'apikey' => $apikey, 'lastlogin' => 0, 'lastvisit' => 0, 'deleted' => 0); $this->_db->addUser($admin_user); # update handmatig het userid $currentId = $dbCon->singleQuery("SELECT id FROM users WHERE username = 'admin'"); $dbCon->exec("UPDATE users SET id = 2 WHERE username = 'admin'"); $dbCon->exec("UPDATE usersettings SET userid = 2 WHERE userid = '%s'", Array( (int) $currentId)); # Geef user 2 (de admin user, naar we van uit gaan) de anon, auth en admin group $dbCon->rawExec("INSERT INTO usergroups(userid,groupid,prio) VALUES(2, 1, 1)"); $dbCon->rawExec("INSERT INTO usergroups(userid,groupid,prio) VALUES(2, 2, 2)"); $dbCon->rawExec("INSERT INTO usergroups(userid,groupid,prio) VALUES(2, 3, 3)"); } # createAdmin /* * Update all users preferences */ function updateUserPreferences() { $userList = $this->_db->listUsers("", 0, 9999999); # loop through every user and fix it foreach($userList['list'] as $user) { # Omdat we vanuit listUsers() niet alle velden meekrijgen # vragen we opnieuw het user record op $user = $this->_db->getUser($user['userid']); # set the users' preferences $this->setSettingIfNot($user['prefs'], 'perpage', 25); $this->setSettingIfNot($user['prefs'], 'date_formatting', 'human'); $this->setSettingIfNot($user['prefs'], 'template', 'we1rdo'); $this->setSettingIfNot($user['prefs'], 'count_newspots', true); $this->setSettingIfNot($user['prefs'], 'keep_seenlist', true); $this->setSettingIfNot($user['prefs'], 'auto_markasread', true); $this->setSettingIfNot($user['prefs'], 'keep_downloadlist', true); $this->setSettingIfNot($user['prefs'], 'keep_watchlist', true); $this->setSettingIfNot($user['prefs'], 'nzb_search_engine', 'nzbindex'); $this->setSettingIfNot($user['prefs'], 'show_filesize', true); $this->setSettingIfNot($user['prefs'], 'show_reportcount', true); $this->setSettingIfNot($user['prefs'], 'show_nzbbutton', true); $this->setSettingIfNot($user['prefs'], 'show_multinzb', true); $this->setSettingIfNot($user['prefs'], 'customcss', ''); $this->setSettingIfNot($user['prefs'], 'newspotdefault_tag', $user['username']); $this->setSettingIfNot($user['prefs'], 'newspotdefault_body', ''); $this->setSettingIfNot($user['prefs'], 'user_language', 'nl_NL'); $this->setSettingIfNot($user['prefs'], 'show_avatars', true); $this->setSettingIfNot($user['prefs'], 'usemailaddress_for_gravatar', true); $this->setSettingIfNot($user['prefs']['nzbhandling'], 'action', 'disable'); $this->setSettingIfNot($user['prefs']['nzbhandling'], 'local_dir', '/tmp'); $this->setSettingIfNot($user['prefs']['nzbhandling'], 'prepare_action', 'merge'); $this->setSettingIfNot($user['prefs']['nzbhandling'], 'command', ''); $this->setSettingIfNot($user['prefs']['nzbhandling']['sabnzbd'], 'url', ''); $this->setSettingIfNot($user['prefs']['nzbhandling']['sabnzbd'], 'apikey', ''); $this->setSettingIfNot($user['prefs']['nzbhandling']['nzbget'], 'host', ''); $this->setSettingIfNot($user['prefs']['nzbhandling']['nzbget'], 'port', ''); $this->setSettingIfNot($user['prefs']['nzbhandling']['nzbget'], 'username', ''); $this->setSettingIfNot($user['prefs']['nzbhandling']['nzbget'], 'password', ''); $this->setSettingIfNot($user['prefs']['nzbhandling']['nzbget'], 'timeout', 15); $this->setSettingIfNot($user['prefs']['notifications']['boxcar'], 'email', ''); $this->setSettingIfNot($user['prefs']['notifications']['growl'], 'host', ''); $this->setSettingIfNot($user['prefs']['notifications']['growl'], 'password', ''); $this->setSettingIfNot($user['prefs']['notifications']['nma'], 'api', ''); $this->setSettingIfNot($user['prefs']['notifications']['notifo'], 'username', ''); $this->setSettingIfNot($user['prefs']['notifications']['notifo'], 'api', ''); $this->setSettingIfNot($user['prefs']['notifications']['prowl'], 'apikey', ''); $this->setSettingIfNot($user['prefs']['notifications']['twitter'], 'screen_name', ''); $this->setSettingIfNot($user['prefs']['notifications']['twitter'], 'request_token', ''); $this->setSettingIfNot($user['prefs']['notifications']['twitter'], 'request_token_secret', ''); $this->setSettingIfNot($user['prefs']['notifications']['twitter'], 'access_token', ''); $this->setSettingIfNot($user['prefs']['notifications']['twitter'], 'access_token_secret', ''); $notifProviders = Notifications_Factory::getActiveServices(); foreach ($notifProviders as $notifProvider) { $this->setSettingIfNot($user['prefs']['notifications'][$notifProvider], 'enabled', false); $this->setSettingIfNot($user['prefs']['notifications'][$notifProvider]['events'], 'watchlist_handled', false); $this->setSettingIfNot($user['prefs']['notifications'][$notifProvider]['events'], 'nzb_handled', false); $this->setSettingIfNot($user['prefs']['notifications'][$notifProvider]['events'], 'retriever_finished', false); $this->setSettingIfNot($user['prefs']['notifications'][$notifProvider]['events'], 'report_posted', false); $this->setSettingIfNot($user['prefs']['notifications'][$notifProvider]['events'], 'spot_posted', false); $this->setSettingIfNot($user['prefs']['notifications'][$notifProvider]['events'], 'user_added', false); } // foreach # make sure a sort preference is defined. An empty field means relevancy $this->setSettingIfNot($user['prefs'], 'defaultsortfield', ''); # oude settings verwijderen $this->unsetSetting($user['prefs'], 'search_url'); $this->unsetSetting($user['prefs']['notifications'], 'libnotify'); # controleren dat de user een geldige RSA key heeft if ($user['userid'] > 2) { $rsaKey = $this->_db->getUserPrivateRsaKey($user['userid']); if (empty($rsaKey)) { # Creer een private en public key paar voor deze user $spotSigning = new SpotSigning(); $userKey = $spotSigning->createPrivateKey($this->_settings->get('openssl_cnf_path')); $this->_db->setUserRsaKeys($user['userid'], $userKey['public'], $userKey['private']); } # if } # if # update the user record in the database $this->_db->setUser($user); } # foreach } # update() /* * Creeer de default security groepen */ function createSecurityGroups() { # DB connectie $dbCon = $this->_db->getDbHandle(); if ($this->_settings->get('securityversion') < 0.01) { /* Truncate de huidige permissies */ $dbCon->rawExec("DELETE FROM securitygroups"); /* Creeer de security groepen */ $dbCon->rawExec("INSERT INTO securitygroups(id,name) VALUES(1, 'Anonymous users')"); $dbCon->rawExec("INSERT INTO securitygroups(id,name) VALUES(2, 'Authenticated users')"); $dbCon->rawExec("INSERT INTO securitygroups(id,name) VALUES(3, 'Administrators')"); } # if } # createSecurityGroups /* * Update de 'default' security groepen hun rechten */ function updateSecurityGroupMembership() { # DB connectie $dbCon = $this->_db->getDbHandle(); if ($this->_settings->get('securityversion') < 0.01) { /* Truncate de huidige permissies */ $dbCon->rawExec("DELETE FROM grouppermissions"); /* Default permissions for anonymous users */ $anonPerms = array(SpotSecurity::spotsec_view_spots_index, SpotSecurity::spotsec_perform_login, SpotSecurity::spotsec_perform_search, SpotSecurity::spotsec_view_spotdetail, SpotSecurity::spotsec_retrieve_nzb, SpotSecurity::spotsec_view_spotimage, SpotSecurity::spotsec_view_statics, SpotSecurity::spotsec_create_new_user, SpotSecurity::spotsec_view_comments, SpotSecurity::spotsec_view_spotcount_total); foreach($anonPerms as $anonPerm) { $dbCon->rawExec("INSERT INTO grouppermissions(groupid,permissionid) VALUES(1, " . $anonPerm . ")"); } # foreach /* Default permissions for authenticated users */ $authedPerms = array(SpotSecurity::spotsec_download_integration, SpotSecurity::spotsec_mark_spots_asread, SpotSecurity::spotsec_view_rssfeed, SpotSecurity::spotsec_edit_own_userprefs, SpotSecurity::spotsec_edit_own_user, SpotSecurity::spotsec_post_comment, SpotSecurity::spotsec_perform_logout, SpotSecurity::spotsec_use_sabapi, SpotSecurity::spotsec_keep_own_watchlist, SpotSecurity::spotsec_keep_own_downloadlist, SpotSecurity::spotsec_keep_own_seenlist, SpotSecurity::spotsec_view_spotcount_filtered, SpotSecurity::spotsec_select_template, SpotSecurity::spotsec_consume_api); foreach($authedPerms as $authedPerm) { $dbCon->rawExec("INSERT INTO grouppermissions(groupid,permissionid) VALUES(2, " . $authedPerm . ")"); } # foreach /* Default permissions for administrative users */ $adminPerms = array(SpotSecurity::spotsec_list_all_users, SpotSecurity::spotsec_retrieve_spots, SpotSecurity::spotsec_edit_other_users); foreach($adminPerms as $adminPerm) { $dbCon->rawExec("INSERT INTO grouppermissions(groupid,permissionid) VALUES(3, " . $adminPerm . ")"); } # foreach } # if # We voegen nog extra security toe voor de logged in user, deze mag gebruik # maken van een aantal paginas via enkel api authenticatie if ($this->_settings->get('securityversion') < 0.02) { $dbCon->rawExec("DELETE FROM grouppermissions WHERE permissionid = " . SpotSecurity::spotsec_consume_api . " AND objectid in ('rss', 'newznabapi', 'getnzb', 'getspot')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_consume_api . ", 'rss')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_consume_api . ", 'newznabapi')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_consume_api . ", 'getnzb')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_consume_api . ", 'getspot')"); } # if # We voegen nog extra security toe voor de logged in user, deze mag gebruik # maken van een aantal download integration settings. De admin user mag ze van # allemaal (tot nu toe bekent) gebruik maken. if ($this->_settings->get('securityversion') < 0.03) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_download_integration . ", 'disable')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_download_integration . ", 'client-sabnzbd')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(3, " . SpotSecurity::spotsec_download_integration . ", 'push-sabnzbd')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(3, " . SpotSecurity::spotsec_download_integration . ", 'save')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(3, " . SpotSecurity::spotsec_download_integration . ", 'runcommand')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(3, " . SpotSecurity::spotsec_download_integration . ", 'nzbget')"); } # if # We voegen nog extra security toe voor de admin user, deze mag users wissen en # groepen van users aanpassen if ($this->_settings->get('securityversion') < 0.06) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(3, " . SpotSecurity::spotsec_delete_user . ")"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(3, " . SpotSecurity::spotsec_edit_groupmembership . ")"); } # if # We voegen nog extra security toe voor de admin user, deze mag group membership van # een user tonen, en securitygroepen inhoudelijk wijzigen if ($this->_settings->get('securityversion') < 0.07) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(3, " . SpotSecurity::spotsec_display_groupmembership . ")"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(3, " . SpotSecurity::spotsec_edit_securitygroups . ")"); } # if # We voegen nog extra security toe voor notificaties if ($this->_settings->get('securityversion') < 0.08) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_services . ")"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_services . ", 'email')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(3, " . SpotSecurity::spotsec_send_notifications_services . ", 'growl')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_services . ", 'notifo')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_services . ", 'prowl')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_types . ")"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_types . ", 'nzb_handled')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(3, " . SpotSecurity::spotsec_send_notifications_types . ", 'retriever_finished')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(3, " . SpotSecurity::spotsec_send_notifications_types . ", 'user_added')"); } # if # We voegen nog extra security toe voor custom stylesheets if ($this->_settings->get('securityversion') < 0.09) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(2, " . SpotSecurity::spotsec_allow_custom_stylesheet . ")"); } # if # We voegen nog extra security toe voor watchlist notificaties en een vergeten NZB download if ($this->_settings->get('securityversion') < 0.10) { $dbCon->rawExec("DELETE FROM grouppermissions WHERE permissionid = " . SpotSecurity::spotsec_send_notifications_services . " AND objectid = 'libnotify'"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_types . ", 'watchlist_handled')"); $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_consume_api . ", 'getnzbmobile')"); } # if # Twitter toegevoegd if ($this->_settings->get('securityversion') < 0.11) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_services . ", 'twitter')"); } # if # Zelf filters kunnen wijzigen if ($this->_settings->get('securityversion') < 0.12) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(2, " . SpotSecurity::spotsec_keep_own_filters . ")"); } # if # Filters als default in kunnen stellen voor de anonymous user if ($this->_settings->get('securityversion') < 0.13) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(3, " . SpotSecurity::spotsec_set_filters_as_default . ")"); } # if # Downloads kunnen wissen is een apart recht geworden (issue #935) if ($this->_settings->get('securityversion') < 0.14) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid,objectid) VALUES(3, " . SpotSecurity::spotsec_keep_own_downloadlist . ", 'erasedls')"); } # if # Spam reporting toegevoegd if ($this->_settings->get('securityversion') < 0.15) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(2, " . SpotSecurity::spotsec_report_spam . ")"); } # if # Nieuwe spot posten toegevoegd if ($this->_settings->get('securityversion') < 0.16) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(2, " . SpotSecurity::spotsec_post_spot . ")"); } # if # Notify My Android toegevoegd if ($this->_settings->get('securityversion') < 0.17) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_services . ", 'nma')"); } # if # Notificatie bij Spot Posten if ($this->_settings->get('securityversion') < 0.18) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_types . ", 'spot_posted')"); } # if # Notificatie bij Report Posten if ($this->_settings->get('securityversion') < 0.19) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_types . ", 'report_posted')"); } # if # Spotters kunnen blacklisten if ($this->_settings->get('securityversion') < 0.20) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(2, " . SpotSecurity::spotsec_blacklist_spotter . ")"); } # if # Anonymous users mag welcomemail versturen if ($this->_settings->get('securityversion') < 0.21) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(1, " . SpotSecurity::spotsec_send_notifications_services . ", 'welcomemail')"); } # if # Boxcar toegevoegd if ($this->_settings->get('securityversion') < 0.22) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid, objectid) VALUES(2, " . SpotSecurity::spotsec_send_notifications_services . ", 'boxcar')"); } # if # Statistieken toegevoegd if ($this->_settings->get('securityversion') < 0.23) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(2, " . SpotSecurity::spotsec_view_statistics . ")"); } # if # Showing of avatars is an security right so administrators could globally disable this if ($this->_settings->get('securityversion') < 0.24) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid,objectid) VALUES(1, " . SpotSecurity::spotsec_view_spotimage . ", 'avatar')"); } # if # Showing the Spotweb updates is a security setting because it compares the current Spotweb version with the latest one it could be seen as # information disclosure if ($this->_settings->get('securityversion') < 0.25) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(3, " . SpotSecurity::spotsec_view_spotweb_updates . ")"); } # if # Settings if ($this->_settings->get('securityversion') < 0.26) { $dbCon->rawExec("INSERT IGNORE INTO grouppermissions(groupid,permissionid) VALUES(3, " . SpotSecurity::spotsec_edit_settings . ")"); } # if } # updateSecurityGroups /* * Update user filters */ function updateUserFilters() { if (($this->_settings->get('securityversion') < 0.12)) { # DB connectie $dbCon = $this->_db->getDbHandle(); # delete all existing filters $dbCon->rawExec("DELETE FROM filters WHERE filtertype = 'filter'"); $userList = $this->_db->listUsers("", 0, 9999999); # loop through every user and fix it foreach($userList['list'] as $user) { /* Beeld */ $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Beeld', 'film', 0, 0, 'cat0_z0')"); $beeldFilterId = $dbCon->lastInsertId('filters'); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'DivX', 'divx', 0, " . $beeldFilterId . ", 'cat0_z0_a0')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'WMV', 'wmv', 1, " . $beeldFilterId . ", 'cat0_z0_a1')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'MPEG', 'mpg', 2, " . $beeldFilterId . ", 'cat0_z0_a2')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'DVD', 'dvd', 3, " . $beeldFilterId . ", 'cat0_z0_a3,cat0_z0_a10')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'HD', 'hd', 4, " . $beeldFilterId . ", 'cat0_z0_a4,cat0_z0_a6,cat0_z0_a7,cat0_z0_a8,cat0_z0_a9')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Series', 'tv', 5, " . $beeldFilterId . ", 'cat0_z1')"); /* Boeken */ $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Boeken', 'book', 6, " . $beeldFilterId . ", 'cat0_z2')"); $boekenFilterId = $dbCon->lastInsertId('filters'); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Nederlands', 'book', 0, " . $boekenFilterId . ", 'cat0_z2_c11')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Engels', 'book', 1, " . $boekenFilterId . ", 'cat0_z2_c10')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Anders', 'book', 2, " . $boekenFilterId . ", 'cat0_z2,~cat0_z2_c10,~cat0_z2_c11')"); /* Erotiek */ $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Erotiek', 'female', 7, " . $beeldFilterId. ", 'cat0_z3')"); $erotiekFilterId = $dbCon->lastInsertId('filters'); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Hetero', 'female', 0, " . $erotiekFilterId . ", 'cat0_z3_d75,cat0_z3_d23')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Homo', 'female', 1, " . $erotiekFilterId . ", 'cat0_z3_d74,cat0_z3_d24')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Lesbo', 'female', 2, " . $erotiekFilterId . ", 'cat0_z3_d73,cat0_z3_d25')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Bi', 'female', 3, " . $erotiekFilterId . ", 'cat0_z3_d72,cat0_z3_d26')"); /* Muziek */ $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Muziek', 'music', 2, 0, 'cat1')"); $muziekFilterId = $dbCon->lastInsertId('filters'); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Compressed', 'music', 0, " . $muziekFilterId . ", 'cat1_a0,cat1_a3,cat1_a5,cat1_a6')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Lossless', 'music', 1, " . $muziekFilterId . ", 'cat1_a2,cat1_a4,cat1_a7,cat1_a8')"); /* Spellen */ $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Spellen', 'controller', 3, 0, 'cat2')"); $gameFilterId = $dbCon->lastInsertId('filters'); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Windows', 'windows', 0, " . $gameFilterId . ", 'cat2_a0')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Mac / Linux', 'linux', 1, " . $gameFilterId . ", 'cat2_a1,cat2_a2')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Playstation', 'playstation', 2, " . $gameFilterId . ", 'cat2_a3,cat2_a4,cat2_a5,cat2_a12')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'XBox', 'xbox', 3, " . $gameFilterId . ", 'cat2_a6,cat2_a7')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Nintendo', 'nintendo_ds', 4, " . $gameFilterId . ", 'cat2_a8,cat2_a9,cat2_a10,cat2_a11')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Smartphone / PDA', 'pda', 5, " . $gameFilterId . ", 'cat2_a13,cat2_a14,cat2_a15')"); /* Applicaties */ $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Applicaties', 'application', 4, 0, 'cat3')"); $appFilterId = $dbCon->lastInsertId('filters'); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Windows', 'vista', 0, " . $appFilterId . ", 'cat3_a0')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'Mac / Linux / OS2', 'linux', 1, " . $appFilterId . ", 'cat3_a1,cat3_a2,cat3_a3')"); $dbCon->rawExec("INSERT INTO filters(userid,filtertype,title,icon,torder,tparent,tree) VALUES(" . $user['userid'] . ", 'filter', 'PDA / Navigatie', 'pda', 2, " . $appFilterId . ", 'cat3_a4,cat3_a5,cat3_a6,cat3_a7')"); } # foreach } # if } # updateUserFilters /* * Update de huidige versie van de settings */ function updateSecurityVersion() { # Lelijke truc om de class autoloader de SpotSecurity klasse te laten laden if (SpotSecurity::spotsec_perform_login == 0) { } ; $this->_settings->set('securityversion', SPOTWEB_SECURITY_VERSION); } # updateSecurityVersion /* * Set een setting alleen als hij nog niet bestaat */ function setSettingIfNot(&$pref, $name, $value) { if (isset($pref[$name])) { return ; } # if $pref[$name] = $value; } # setSettingIfNot /* * Verwijdert een gekozen setting */ function unsetSetting(&$pref, $name) { if (!isset($pref[$name])) { return ; } # if unset($pref[$name]); } # setSettingIfNot } # SpotUserUpgrader debian/db-update/v20111210/lib/SpotDb.php0000644000000000000000000025243412267045571014605 0ustar _dbsettings = $db; } # __ctor /* * Open connectie naar de database (basically factory), de 'engine' wordt uit de * settings gehaald die mee worden gegeven in de ctor. */ function connect() { SpotTiming::start(__FUNCTION__); /* * Erase username/password so it won't show up in any stacktrace */ # SQlite heeft geen username gedefinieerd if (isset($this->_dbsettings['user'])) { $tmpUser = $this->_dbsettings['user']; $this->_dbsettings['user'] = '*FILTERED*'; } # if # en ook geen pass if (isset($this->_dbsettings['pass'])) { $tmpPass = $this->_dbsettings['pass']; $this->_dbsettings['pass'] = '*FILTERED*'; } # if switch ($this->_dbsettings['engine']) { case 'mysql' : $this->_conn = new dbeng_mysql($this->_dbsettings['host'], $tmpUser, $tmpPass, $this->_dbsettings['dbname']); break; case 'pdo_mysql': $this->_conn = new dbeng_pdo_mysql($this->_dbsettings['host'], $tmpUser, $tmpPass, $this->_dbsettings['dbname']); break; case 'pdo_pgsql' : $this->_conn = new dbeng_pdo_pgsql($this->_dbsettings['host'], $tmpUser, $tmpPass, $this->_dbsettings['dbname']); break; case 'pdo_sqlite': $this->_conn = new dbeng_pdo_sqlite($this->_dbsettings['path']); break; default : throw new Exception('Unknown DB engine specified, please choose pdo_sqlite, mysql or pdo_mysql'); } # switch $this->_conn->connect(); SpotTiming::stop(__FUNCTION__); } # connect /* * Geeft het database connectie object terug */ function getDbHandle() { return $this->_conn; } # getDbHandle /* * Haalt alle settings op uit de database */ function getAllSettings() { $dbSettings = $this->_conn->arrayQuery('SELECT name,value,serialized FROM settings'); $tmpSettings = array(); foreach($dbSettings as $item) { if ($item['serialized']) { $item['value'] = unserialize($item['value']); } # if $tmpSettings[$item['name']] = $item['value']; } # foreach return $tmpSettings; } # getAllSettings function getMaxPacketSize() { if ($this->_maxPacketSize == null) { $packet = -1; switch ($this->_dbsettings['engine']) { case 'mysql' : case 'pdo_mysql' : $packet = $this->_conn->arrayQuery("SHOW VARIABLES LIKE 'max_allowed_packet'"); $packet = $packet[0]['Value']; break; } # switch $this->_maxPacketSize = $packet; } # if return $this->_maxPacketSize; } # getMaxPacketSize /* * Controleer of een messageid niet al eerder gebruikt is door ons om hier * te posten */ function isNewSpotMessageIdUnique($messageid) { /* * We use a union between our own messageids and the messageids we already * know to prevent a user from spamming the spotweb system by using existing * but valid spots */ $tmpResult = $this->_conn->singleQuery("SELECT messageid FROM commentsposted WHERE messageid = '%s' UNION SELECT messageid FROM spots WHERE messageid = '%s'", Array($messageid, $messageid)); return (empty($tmpResult)); } # isNewSpotMessageIdUnique /* * Add the posted spot to the database */ function addPostedSpot($userId, $spot, $fullXml) { $this->_conn->modify( "INSERT INTO spotsposted(ouruserid, messageid, stamp, title, tag, category, subcats, fullxml) VALUES(%d, '%s', %d, '%s', '%s', %d, '%s', '%s')", Array((int) $userId, $spot['newmessageid'], (int) time(), $spot['title'], $spot['tag'], (int) $spot['category'], implode(',', $spot['subcatlist']), $fullXml)); } # addPostedSpot /* * Controleer of een messageid niet al eerder gebruikt is door ons om hier * te posten */ function isCommentMessageIdUnique($messageid) { $tmpResult = $this->_conn->singleQuery("SELECT messageid FROM commentsposted WHERE messageid = '%s'", Array($messageid)); return (empty($tmpResult)); } # isCommentMessageIdUnique /* * Controleer of een messageid niet al eerder gebruikt is door ons om hier * te posten */ function isReportMessageIdUnique($messageid) { $tmpResult = $this->_conn->singleQuery("SELECT messageid FROM reportsposted WHERE messageid = '%s'", Array($messageid)); return (empty($tmpResult)); } # isReportMessageIdUnique /* * Controleer of een user reeds een spamreport heeft geplaatst voor de betreffende spot */ function isReportPlaced($messageid, $userId) { $tmpResult = $this->_conn->singleQuery("SELECT messageid FROM reportsposted WHERE inreplyto = '%s' AND ouruserid = %d", Array($messageid, $userId)); return (!empty($tmpResult)); } #isReportPlaced /* * Sla het gepostte comment op van deze user */ function addPostedComment($userId, $comment) { $this->_conn->modify( "INSERT INTO commentsposted(ouruserid, messageid, inreplyto, randompart, rating, body, stamp) VALUES('%d', '%s', '%s', '%s', '%d', '%s', %d)", Array((int) $userId, $comment['newmessageid'], $comment['inreplyto'], $comment['randomstr'], (int) $comment['rating'], $comment['body'], (int) time())); } # addPostedComment /* * Sla het gepostte report op van deze user */ function addPostedReport($userId, $report) { $this->_conn->modify( "INSERT INTO reportsposted(ouruserid, messageid, inreplyto, randompart, body, stamp) VALUES('%d', '%s', '%s', '%s', '%s', %d)", Array((int) $userId, $report['newmessageid'], $report['inreplyto'], $report['randomstr'], $report['body'], (int) time())); } # addPostedReport /* * Verwijder een setting */ function removeSetting($name) { $this->_conn->exec("DELETE FROM settings WHERE name = '%s'", Array($name)); } # removeSetting /* * Update setting */ function updateSetting($name, $value) { # zet het eventueel serialized in de database als dat nodig is if ((is_array($value) || is_object($value))) { $value = serialize($value); $serialized = true; } else { $serialized = false; } # if switch ($this->_dbsettings['engine']) { case 'mysql' : case 'pdo_mysql' : { $this->_conn->modify("INSERT INTO settings(name,value,serialized) VALUES ('%s', '%s', '%s') ON DUPLICATE KEY UPDATE value = '%s', serialized = %s", Array($name, $value, $this->bool2dt($serialized), $value, $this->bool2dt($serialized))); break; } # mysql default : { $this->_conn->exec("UPDATE settings SET value = '%s', serialized = '%s' WHERE name = '%s'", Array($value, $this->bool2dt($serialized), $name)); if ($this->_conn->rows() == 0) { $this->_conn->modify("INSERT INTO settings(name,value,serialized) VALUES('%s', '%s', '%s')", Array($name, $value, $this->bool2dt($serialized))); } # if break; } # default } # switch } # updateSetting /* * Haalt een session op uit de database */ function getSession($sessionid, $userid) { $tmp = $this->_conn->arrayQuery( "SELECT s.sessionid as sessionid, s.userid as userid, s.hitcount as hitcount, s.lasthit as lasthit, s.ipaddr as ipaddr FROM sessions AS s WHERE (sessionid = '%s') AND (userid = %d)", Array($sessionid, (int) $userid)); if (!empty($tmp)) { return $tmp[0]; } # if return false; } # getSession /* * Creert een sessie */ function addSession($session) { $this->_conn->modify( "INSERT INTO sessions(sessionid, userid, hitcount, lasthit, ipaddr) VALUES('%s', %d, %d, %d, '%s')", Array($session['sessionid'], (int) $session['userid'], (int) $session['hitcount'], (int) $session['lasthit'], $session['ipaddr'])); } # addSession /* * Haalt een session op uit de database */ function deleteSession($sessionid) { $this->_conn->modify( "DELETE FROM sessions WHERE sessionid = '%s'", Array($sessionid)); } # deleteSession /* * Haalt een session op uit de database */ function deleteAllUserSessions($userid) { $this->_conn->modify( "DELETE FROM sessions WHERE userid = %d", Array( (int) $userid)); } # deleteAllUserSessions /* * Haalt een session op uit de database */ function deleteExpiredSessions($maxLifeTime) { $this->_conn->modify( "DELETE FROM sessions WHERE lasthit < %d", Array(time() - $maxLifeTime)); } # deleteExpiredSessions /* * Update de last hit van een session */ function hitSession($sessionid) { $this->_conn->modify("UPDATE sessions SET hitcount = hitcount + 1, lasthit = %d WHERE sessionid = '%s'", Array(time(), $sessionid)); } # hitSession /* * Checkt of een username al bestaat */ function usernameExists($username) { $tmpResult = $this->_conn->singleQuery("SELECT username FROM users WHERE username = '%s'", Array($username)); return (!empty($tmpResult)); } # usernameExists /* * Checkt of een emailaddress al bestaat */ function userEmailExists($mail) { $tmpResult = $this->_conn->singleQuery("SELECT id FROM users WHERE mail = '%s'", Array($mail)); if (!empty($tmpResult)) { return $tmpResult; } # if return false; } # userEmailExists /* * Haalt een user op uit de database */ function getUser($userid) { $tmp = $this->_conn->arrayQuery( "SELECT u.id AS userid, u.username AS username, u.firstname AS firstname, u.lastname AS lastname, u.mail AS mail, u.apikey AS apikey, u.deleted AS deleted, u.lastlogin AS lastlogin, u.lastvisit AS lastvisit, u.lastread AS lastread, u.lastapiusage AS lastapiusage, s.publickey AS publickey, s.avatar AS avatar, s.otherprefs AS prefs FROM users AS u JOIN usersettings s ON (u.id = s.userid) WHERE u.id = %d AND NOT DELETED", Array( (int) $userid )); if (!empty($tmp)) { # Other preferences worden serialized opgeslagen in de database $tmp[0]['prefs'] = unserialize($tmp[0]['prefs']); return $tmp[0]; } # if return false; } # getUser /* * Haalt een user op uit de database */ function listUsers($username, $pageNr, $limit) { SpotTiming::start(__FUNCTION__); $offset = (int) $pageNr * (int) $limit; $tmpResult = $this->_conn->arrayQuery( "SELECT u.id AS userid, u.username AS username, u.firstname AS firstname, u.lastname AS lastname, u.mail AS mail, u.lastlogin AS lastlogin, COALESCE((SELECT MAX(lasthit) FROM sessions WHERE userid = u.id), lastvisit) as lastvisit, (SELECT ipaddr FROM sessions WHERE userid = u.id ORDER BY lasthit DESC LIMIT 1) as lastipaddr, s.otherprefs AS prefs FROM users AS u JOIN usersettings s ON (u.id = s.userid) WHERE (username LIKE '%" . $this->safe($username) . "%') AND (NOT DELETED) LIMIT " . (int) ($limit + 1) ." OFFSET " . (int) $offset); if (!empty($tmpResult)) { # Other preferences worden serialized opgeslagen in de database $tmpResultCount = count($tmpResult); for($i = 0; $i < $tmpResultCount; $i++) { $tmpResult[$i]['prefs'] = unserialize($tmpResult[$i]['prefs']); } # for } # if # als we meer resultaten krijgen dan de aanroeper van deze functie vroeg, dan # kunnen we er van uit gaan dat er ook nog een pagina is voor de volgende aanroep $hasMore = (count($tmpResult) > $limit); if ($hasMore) { # verwijder het laatste, niet gevraagde, element array_pop($tmpResult); } # if SpotTiming::stop(__FUNCTION__, array($username, $pageNr, $limit)); return array('list' => $tmpResult, 'hasmore' => $hasMore); } # listUsers /* * Disable/delete een user. Echt wissen willen we niet * omdat eventuele comments dan niet meer te traceren * zouden zijn waardoor anti-spam maatregelen erg lastig * worden */ function deleteUser($userid) { $this->_conn->modify("UPDATE users SET deleted = true WHERE id = '%s'", Array( (int) $userid)); } # deleteUser /* * Update de informatie over een user behalve het password */ function setUser($user) { # eerst updaten we de users informatie $this->_conn->modify("UPDATE users SET firstname = '%s', lastname = '%s', mail = '%s', apikey = '%s', lastlogin = %d, lastvisit = %d, lastread = %d, lastapiusage = %d, deleted = '%s' WHERE id = %d", Array($user['firstname'], $user['lastname'], $user['mail'], $user['apikey'], (int) $user['lastlogin'], (int) $user['lastvisit'], (int) $user['lastread'], (int) $user['lastapiusage'], $this->bool2dt($user['deleted']), (int) $user['userid'])); # daarna updaten we zijn preferences $this->_conn->modify("UPDATE usersettings SET otherprefs = '%s' WHERE userid = '%s'", Array(serialize($user['prefs']), (int) $user['userid'])); } # setUser /* * Stel users' password in */ function setUserPassword($user) { $this->_conn->modify("UPDATE users SET passhash = '%s' WHERE id = '%s'", Array($user['passhash'], (int) $user['userid'])); } # setUserPassword /* * Vul de public en private key van een user in, alle andere * user methodes kunnen dit niet updaten omdat het altijd * een paar moet zijn */ function setUserRsaKeys($userId, $publicKey, $privateKey) { # eerst updaten we de users informatie $this->_conn->modify("UPDATE usersettings SET publickey = '%s', privatekey = '%s' WHERE userid = '%s'", Array($publicKey, $privateKey, $userId)); } # setUserRsaKeys /* * Vraagt de users' private key op */ function getUserPrivateRsaKey($userId) { return $this->_conn->singleQuery("SELECT privatekey FROM usersettings WHERE userid = '%s'", Array($userId)); } # getUserPrivateRsaKey /* * Voeg een user toe */ function addUser($user) { $this->_conn->modify("INSERT INTO users(username, firstname, lastname, passhash, mail, apikey, lastread, deleted) VALUES('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')", Array($user['username'], $user['firstname'], $user['lastname'], $user['passhash'], $user['mail'], $user['apikey'], $this->getMaxMessageTime(), $this->bool2dt(false))); # We vragen nu het userrecord terug op om het userid te krijgen, # niet echt een mooie oplossing, maar we hebben blijkbaar geen # lastInsertId() exposed in de db klasse $user['userid'] = $this->_conn->singleQuery("SELECT id FROM users WHERE username = '%s'", Array($user['username'])); # en voeg een usersettings record in $this->_conn->modify("INSERT INTO usersettings(userid, privatekey, publickey, otherprefs) VALUES('%s', '', '', 'a:0:{}')", Array((int)$user['userid'])); return $user; } # addUser /* * Kan de user inloggen met opgegeven password of API key? * * Een userid als de user gevonden kan worden, of false voor failure */ function authUser($username, $passhash) { if ($username === false) { $tmp = $this->_conn->arrayQuery("SELECT id FROM users WHERE apikey = '%s' AND NOT DELETED", Array($passhash)); } else { $tmp = $this->_conn->arrayQuery("SELECT id FROM users WHERE username = '%s' AND passhash = '%s' AND NOT DELETED", Array($username, $passhash)); } # if return (empty($tmp)) ? false : $tmp[0]['id']; } # authUser /* * Update of insert the maximum article id in de database. */ function setMaxArticleId($server, $maxarticleid) { switch ($this->_dbsettings['engine']) { case 'mysql' : case 'pdo_mysql' : { $this->_conn->modify("INSERT INTO nntp(server, maxarticleid) VALUES ('%s', '%s') ON DUPLICATE KEY UPDATE maxarticleid = '%s'", Array($server, (int) $maxarticleid, (int) $maxarticleid)); break; } # mysql default : { $this->_conn->exec("UPDATE nntp SET maxarticleid = '%s' WHERE server = '%s'", Array((int) $maxarticleid, $server)); if ($this->_conn->rows() == 0) { $this->_conn->modify("INSERT INTO nntp(server, maxarticleid) VALUES('%s', '%s')", Array($server, (int) $maxarticleid)); } # if break; } # default } # switch } # setMaxArticleId() /* * Vraag het huidige articleid (van de NNTP server) op, als die nog * niet bestaat, voeg dan een nieuw record toe en zet die op 0 */ function getMaxArticleId($server) { $artId = $this->_conn->singleQuery("SELECT maxarticleid FROM nntp WHERE server = '%s'", Array($server)); if ($artId == null) { $this->setMaxArticleId($server, 0); $artId = 0; } # if return $artId; } # getMaxArticleId /* * Returns the highest messageid from server */ function getMaxMessageId($headers) { if ($headers == 'headers') { $msgIds = $this->_conn->arrayQuery("SELECT messageid FROM spots ORDER BY id DESC LIMIT 5000"); } elseif ($headers == 'comments') { $msgIds = $this->_conn->arrayQuery("SELECT messageid FROM commentsxover ORDER BY id DESC LIMIT 5000"); } elseif ($headers == 'reports') { $msgIds = $this->_conn->arrayQuery("SELECT messageid FROM reportsxover ORDER BY id DESC LIMIT 5000"); } else { throw new Exception("getMaxMessageId() header-type value is unknown"); } # else if ($msgIds == null) { return array(); } # if $tempMsgIdList = array(); $msgIdCount = count($msgIds); for($i = 0; $i < $msgIdCount; $i++) { $tempMsgIdList['<' . $msgIds[$i]['messageid'] . '>'] = 1; } # for return $tempMsgIdList; } # func. getMaxMessageId function getMaxMessageTime() { $stamp = $this->_conn->singleQuery("SELECT MAX(stamp) AS stamp FROM spots"); if ($stamp == null) { $stamp = time(); } # if return $stamp; } # getMaxMessageTime() /* * Geeft een database engine specifieke text-match (bv. fulltxt search) query onderdeel terug */ function createTextQuery($fieldList) { return $this->_conn->createTextQuery($fieldList); } # createTextQuery() /* * Geef terug of de huidige nntp server al bezig is volgens onze eigen database */ function isRetrieverRunning($server) { $artId = $this->_conn->singleQuery("SELECT nowrunning FROM nntp WHERE server = '%s'", Array($server)); return ((!empty($artId)) && ($artId > (time() - 900))); } # isRetrieverRunning /* * Geef terug of de huidige nntp server al bezig is volgens onze eigen database */ function setRetrieverRunning($server, $isRunning) { if ($isRunning) { $runTime = time(); } else { $runTime = 0; } # if switch ($this->_dbsettings['engine']) { case 'mysql' : case 'pdo_mysql' : { $this->_conn->modify("INSERT INTO nntp (server, nowrunning) VALUES ('%s', %d) ON DUPLICATE KEY UPDATE nowrunning = %d", Array($server, (int) $runTime, (int) $runTime)); break; } # mysql default : { $this->_conn->modify("UPDATE nntp SET nowrunning = %d WHERE server = '%s'", Array((int) $runTime, $server)); if ($this->_conn->rows() == 0) { $this->_conn->modify("INSERT INTO nntp(server, nowrunning) VALUES('%s', %d)", Array($server, (int) $runTime)); } # if } # default } # switch } # setRetrieverRunning /* * Remove extra spots */ function removeExtraSpots($messageId) { # vraag eerst het id op $spot = $this->getSpotHeader($messageId); /* * The spot might be empty because - for example, the spot * is moderated (and hence deleted), the highest spot retrieved * might be missing from the database because of the spam cleanup. * * Ignore this error */ if (empty($spot)) { return ; } # if # en wis nu alles wat 'jonger' is dan deze spot switch ($this->_dbsettings['engine']) { # geen join delete omdat sqlite dat niet kan case 'pdo_pgsql' : case 'pdo_sqlite' : { $this->_conn->modify("DELETE FROM spotsfull WHERE messageid IN (SELECT messageid FROM spots WHERE id > %d)", Array($spot['id'])); $this->_conn->modify("DELETE FROM spots WHERE id > %d", Array($spot['id'])); break; } # case default : { $this->_conn->modify("DELETE FROM spots, spotsfull USING spots LEFT JOIN spotsfull on spots.messageid=spotsfull.messageid WHERE spots.id > %d", array($spot['id'])); } # default } # switch } # removeExtraSpots /* * Remove extra comments */ function removeExtraComments($messageId) { # vraag eerst het id op $commentId = $this->_conn->singleQuery("SELECT id FROM commentsxover WHERE messageid = '%s'", Array($messageId)); # als deze spot leeg is, is er iets raars aan de hand if (empty($commentId)) { throw new Exception("Our highest comment is not in the database!?"); } # if # en wis nu alles wat 'jonger' is dan deze spot $this->_conn->modify("DELETE FROM commentsxover WHERE id > %d", Array($commentId)); } # removeExtraComments /* * Remove extra comments */ function removeExtraReports($messageId) { # vraag eerst het id op $reportId = $this->_conn->singleQuery("SELECT id FROM reportsxover WHERE messageid = '%s'", Array($messageId)); # als deze report leeg is, is er iets raars aan de hand if (empty($reportId)) { throw new Exception("Our highest report is not in the database!?"); } # if # en wis nu alles wat 'jonger' is dan deze spot $this->_conn->modify("DELETE FROM reportsxover WHERE id > %d", Array($reportId)); } # removeExtraReports /* * Zet de tijd/datum wanneer retrieve voor het laatst geupdate heeft */ function setLastUpdate($server) { return $this->_conn->modify("UPDATE nntp SET lastrun = '%d' WHERE server = '%s'", Array(time(), $server)); } # getLastUpdate /* * Geef de datum van de laatste update terug */ function getLastUpdate($server) { return $this->_conn->singleQuery("SELECT lastrun FROM nntp WHERE server = '%s'", Array($server)); } # getLastUpdate /** * Geef het aantal spots terug dat er op dit moment in de db zit */ function getSpotCount($sqlFilter) { SpotTiming::start(__FUNCTION__); if (empty($sqlFilter)) { $query = "SELECT COUNT(1) FROM spots AS s"; } else { $query = "SELECT COUNT(1) FROM spots AS s LEFT JOIN spotsfull AS f ON s.messageid = f.messageid LEFT JOIN spotstatelist AS l ON s.messageid = l.messageid WHERE " . $sqlFilter; } # else $cnt = $this->_conn->singleQuery($query); SpotTiming::stop(__FUNCTION__, array($sqlFilter)); if ($cnt == null) { return 0; } else { return $cnt; } # if } # getSpotCount function getSpotCountPerHour($limit) { $filter = ($limit) ? "WHERE stamp > " . strtotime("-1 " . $limit) : ''; switch ($this->_dbsettings['engine']) { case 'pdo_pgsql' : $rs = $this->_conn->arrayQuery("SELECT EXTRACT(HOUR FROM to_timestamp(stamp)) AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); break; case 'pdo_sqlite' : $rs = $this->_conn->arrayQuery("SELECT strftime('%H', time(stamp, 'unixepoch')) AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); break; default : $rs = $this->_conn->arrayQuery("SELECT EXTRACT(HOUR FROM FROM_UNIXTIME(stamp)) AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); } # switch return $rs; } # getSpotCountPerHour function getSpotCountPerWeekday($limit) { $filter = ($limit) ? "WHERE stamp > " . strtotime("-1 " . $limit) : ''; switch ($this->_dbsettings['engine']) { case 'pdo_pgsql' : $rs = $this->_conn->arrayQuery("SELECT EXTRACT(DOW FROM to_timestamp(stamp)) AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); break; case 'pdo_sqlite' : $rs = $this->_conn->arrayQuery("SELECT strftime('%w', time(stamp, 'unixepoch')) AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); break; default : $rs = $this->_conn->arrayQuery("SELECT FROM_UNIXTIME(stamp,'%w') AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); } # switch return $rs; } # getSpotCountPerWeekday function getSpotCountPerMonth($limit) { $filter = ($limit) ? "WHERE stamp > " . strtotime("-1 " . $limit) : ''; switch ($this->_dbsettings['engine']) { case 'pdo_pgsql' : $rs = $this->_conn->arrayQuery("SELECT EXTRACT(MONTH FROM to_timestamp(stamp)) AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); break; case 'pdo_sqlite' : $rs = $this->_conn->arrayQuery("SELECT strftime('%m', time(stamp, 'unixepoch')) AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); break; default : $rs = $this->_conn->arrayQuery("SELECT EXTRACT(MONTH FROM FROM_UNIXTIME(stamp)) AS data, count(*) AS amount FROM spots " . $filter . " GROUP BY data;"); } # switch return $rs; } # getSpotCountPerMonth function getSpotCountPerCategory($limit) { $filter = ($limit) ? "WHERE stamp > " . strtotime("-1 " . $limit) : ''; $rs = $this->_conn->arrayQuery("SELECT category AS data, COUNT(category) AS amount FROM spots " . $filter . " GROUP BY data;"); return $rs; } # getSpotCountPerCategory function getOldestSpotTimestamp() { $rs = $this->_conn->singleQuery("SELECT MIN(stamp) FROM spots;"); return $rs; } # getOldestSpotTimestamp /* * Match set of comments */ function matchCommentMessageIds($hdrList) { # We negeren commentsfull hier een beetje express, als die een # keer ontbreken dan fixen we dat later wel. $idList = array('comment' => array(), 'fullcomment' => array()); # geen message id's gegeven? vraag het niet eens aan de db if (count($hdrList) == 0) { return $idList; } # if # bereid de lijst voor met de queries in de where $msgIdList = ''; foreach($hdrList as $hdr) { $msgIdList .= "'" . substr($this->_conn->safe($hdr['Message-ID']), 1, -1) . "', "; } # foreach $msgIdList = substr($msgIdList, 0, -2); # Omdat MySQL geen full joins kent, doen we het zo $rs = $this->_conn->arrayQuery("SELECT messageid AS comment, '' AS fullcomment FROM commentsxover WHERE messageid IN (" . $msgIdList . ") UNION SELECT '' as comment, messageid AS fullcomment FROM commentsfull WHERE messageid IN (" . $msgIdList . ")"); # en lossen we het hier op foreach($rs as $msgids) { if (!empty($msgids['comment'])) { $idList['comment'][$msgids['comment']] = 1; } # if if (!empty($msgids['fullcomment'])) { $idList['fullcomment'][$msgids['fullcomment']] = 1; } # if } # foreach return $idList; } # matchCommentMessageIds /* * Match set of reports */ function matchReportMessageIds($hdrList) { $idList = array(); # geen message id's gegeven? vraag het niet eens aan de db if (count($hdrList) == 0) { return $idList; } # if # bereid de lijst voor met de queries in de where $msgIdList = ''; foreach($hdrList as $hdr) { $msgIdList .= "'" . substr($this->_conn->safe($hdr['Message-ID']), 1, -1) . "', "; } # foreach $msgIdList = substr($msgIdList, 0, -2); # en vraag alle comments op die we kennen $rs = $this->_conn->arrayQuery("SELECT messageid FROM reportsxover WHERE messageid IN (" . $msgIdList . ")"); # geef hier een array terug die kant en klaar is voor array_search foreach($rs as $msgids) { $idList[$msgids['messageid']] = 1; } # foreach return $idList; } # matchReportMessageIds /* * Match set of spots */ function matchSpotMessageIds($hdrList) { $idList = array('spot' => array(), 'fullspot' => array()); # geen message id's gegeven? vraag het niet eens aan de db if (count($hdrList) == 0) { return $idList; } # if # bereid de lijst voor met de queries in de where $msgIdList = ''; foreach($hdrList as $hdr) { $msgIdList .= "'" . substr($this->_conn->safe($hdr['Message-ID']), 1, -1) . "', "; } # foreach $msgIdList = substr($msgIdList, 0, -2); # Omdat MySQL geen full joins kent, doen we het zo $rs = $this->_conn->arrayQuery("SELECT messageid AS spot, '' AS fullspot FROM spots WHERE messageid IN (" . $msgIdList . ") UNION SELECT '' as spot, messageid AS fullspot FROM spotsfull WHERE messageid IN (" . $msgIdList . ")"); # en lossen we het hier op foreach($rs as $msgids) { if (!empty($msgids['spot'])) { $idList['spot'][$msgids['spot']] = 1; } # if if (!empty($msgids['fullspot'])) { $idList['fullspot'][$msgids['fullspot']] = 1; } # if } # foreach return $idList; } # matchMessageIds /* * Geef alle spots terug in de database die aan $parsedSearch voldoen. * */ function getSpots($ourUserId, $pageNr, $limit, $parsedSearch) { SpotTiming::start(__FUNCTION__); $results = array(); $offset = (int) $pageNr * (int) $limit; # je hebt de zoek criteria (category, titel, etc) $criteriaFilter = ' WHERE (bl.spotterid IS NULL)'; if (!empty($parsedSearch['filter'])) { $criteriaFilter .= ' AND ' . $parsedSearch['filter']; } # if # er kunnen ook nog additionele velden gevraagd zijn door de filter parser # als dat zo is, voeg die dan ook toe $extendedFieldList = ''; foreach($parsedSearch['additionalFields'] as $additionalField) { $extendedFieldList = ', ' . $additionalField . $extendedFieldList; } # foreach # ook additionele tabellen kunnen gevraagd zijn door de filter parser, die # moeten we dan ook toevoegen $additionalTableList = ''; foreach($parsedSearch['additionalTables'] as $additionalTable) { $additionalTableList = ', ' . $additionalTable . $additionalTableList; } # foreach # zelfs additionele joinskunnen gevraagd zijn door de filter parser, die # moeten we dan ook toevoegen $additionalJoinList = ''; foreach($parsedSearch['additionalJoins'] as $additionalJoin) { $additionalJoinList = ' ' . $additionalJoin['jointype'] . ' JOIN ' . $additionalJoin['tablename'] . ' AS ' . $additionalJoin['tablealias'] . ' ON (' . $additionalJoin['joincondition'] . ') '; } # foreach # Nu prepareren we de sorterings lijst $sortFields = $parsedSearch['sortFields']; $sortList = array(); foreach($sortFields as $sortValue) { if (!empty($sortValue)) { # als er gevraagd is om op 'stamp' descending te sorteren, dan draaien we dit # om en voeren de query uit reversestamp zodat we een ASCending sort doen. Dit maakt # het voor MySQL ISAM een stuk sneller if ((strtolower($sortValue['field']) == 's.stamp') && strtolower($sortValue['direction']) == 'desc') { $sortValue['field'] = 's.reversestamp'; $sortValue['direction'] = 'ASC'; } # if $sortList[] = $sortValue['field'] . ' ' . $sortValue['direction']; } # if } # foreach $sortList = implode(', ', $sortList); # en voer de query uit. # We vragen altijd 1 meer dan de gevraagde limit zodat we ook een hasMore boolean flag # kunnen zetten. $tmpResult = $this->_conn->arrayQuery("SELECT s.id AS id, s.messageid AS messageid, s.category AS category, s.poster AS poster, l.download as downloadstamp, l.watch as watchstamp, l.seen AS seenstamp, s.subcata AS subcata, s.subcatb AS subcatb, s.subcatc AS subcatc, s.subcatd AS subcatd, s.subcatz AS subcatz, s.title AS title, s.tag AS tag, s.stamp AS stamp, s.moderated AS moderated, s.filesize AS filesize, s.spotrating AS rating, s.commentcount AS commentcount, s.reportcount AS reportcount, s.spotterid AS spotterid, f.verified AS verified " . $extendedFieldList . " FROM spots AS s " . $additionalTableList . $additionalJoinList . " LEFT JOIN spotstatelist AS l on ((s.messageid = l.messageid) AND (l.ouruserid = " . $this->safe( (int) $ourUserId) . ")) LEFT JOIN spotsfull AS f ON (s.messageid = f.messageid) LEFT JOIN spotteridblacklist as bl ON ((bl.spotterid = s.spotterid) AND ((bl.ouruserid = " . $this->safe( (int) $ourUserId) . ") OR (bl.ouruserid = -1))) " . $criteriaFilter . " ORDER BY " . $sortList . " LIMIT " . (int) ($limit + 1) ." OFFSET " . (int) $offset); # als we meer resultaten krijgen dan de aanroeper van deze functie vroeg, dan # kunnen we er van uit gaan dat er ook nog een pagina is voor de volgende aanroep $hasMore = (count($tmpResult) > $limit); if ($hasMore) { # verwijder het laatste, niet gevraagde, element array_pop($tmpResult); } # if SpotTiming::stop(__FUNCTION__, array($ourUserId, $pageNr, $limit, $criteriaFilter)); return array('list' => $tmpResult, 'hasmore' => $hasMore); } # getSpots() /* * Geeft enkel de header van de spot terug */ function getSpotHeader($msgId) { SpotTiming::start(__FUNCTION__); $tmpArray = $this->_conn->arrayQuery("SELECT s.id AS id, s.messageid AS messageid, s.category AS category, s.poster AS poster, s.subcata AS subcata, s.subcatb AS subcatb, s.subcatc AS subcatc, s.subcatd AS subcatd, s.subcatz AS subcatz, s.title AS title, s.tag AS tag, s.stamp AS stamp, s.spotrating AS rating, s.commentcount AS commentcount, s.reportcount AS reportcount, s.moderated AS moderated FROM spots AS s WHERE s.messageid = '%s'", Array($msgId)); if (empty($tmpArray)) { return ; } # if SpotTiming::stop(__FUNCTION__); return $tmpArray[0]; } # getSpotHeader /* * Vraag 1 specifieke spot op, als de volledig spot niet in de database zit * geeft dit NULL terug */ function getFullSpot($messageId, $ourUserId) { SpotTiming::start(__FUNCTION__); $tmpArray = $this->_conn->arrayQuery("SELECT s.id AS id, s.messageid AS messageid, s.category AS category, s.poster AS poster, s.subcata AS subcata, s.subcatb AS subcatb, s.subcatc AS subcatc, s.subcatd AS subcatd, s.subcatz AS subcatz, s.title AS title, s.tag AS tag, s.stamp AS stamp, s.moderated AS moderated, s.spotrating AS rating, s.commentcount AS commentcount, s.reportcount AS reportcount, s.filesize AS filesize, s.spotterid AS spotterid, l.download AS downloadstamp, l.watch as watchstamp, l.seen AS seenstamp, f.verified AS verified, f.usersignature AS \"user-signature\", f.userkey AS \"user-key\", f.xmlsignature AS \"xml-signature\", f.fullxml AS fullxml FROM spots AS s LEFT JOIN spotstatelist AS l on ((s.messageid = l.messageid) AND (l.ouruserid = " . $this->safe( (int) $ourUserId) . ")) JOIN spotsfull AS f ON f.messageid = s.messageid WHERE s.messageid = '%s'", Array($messageId)); if (empty($tmpArray)) { return ; } # if $tmpArray = $tmpArray[0]; # If spot is fully stored in db and is of the new type, we process it to # make it exactly the same as when retrieved using NNTP if (!empty($tmpArray['fullxml']) && (!empty($tmpArray['user-signature']))) { $tmpArray['user-key'] = unserialize(base64_decode($tmpArray['user-key'])); } # if SpotTiming::stop(__FUNCTION__, array($messageId, $ourUserId)); return $tmpArray; } # getFullSpot() /* * Insert commentref, * messageid is het werkelijke commentaar id * nntpref is de id van de spot */ function addComments($comments, $fullComments = array()) { $this->beginTransaction(); # Databases can have a maximum length of statements, so we # split the amount of spots in chunks of 100 if ($this->_dbsettings['engine'] == 'pdo_sqlite') { $chunks = array_chunk($comments, 1); } else { $chunks = array_chunk($comments, 100); } # else foreach($chunks as $comments) { $insertArray = array(); foreach($comments as $comment) { $insertArray[] = vsprintf("('%s', '%s', %d)", Array($this->safe($comment['messageid']), $this->safe($comment['nntpref']), $this->safe($comment['rating']))); } # foreach # Actually insert the batch if (!empty($insertArray)) { $this->_conn->modify("INSERT INTO commentsxover(messageid, nntpref, spotrating) VALUES " . implode(',', $insertArray), array()); } # if } # foreach $this->commitTransaction(); if (!empty($fullComments)) { $this->addFullComments($fullComments); } # if } # addComments /* * Insert commentfull, gaat er van uit dat er al een commentsxover entry is */ function addFullComments($fullComments) { $this->beginTransaction(); # Databases can have a maximum length of statements, so we # split the amount of spots in chunks of 100 if ($this->_dbsettings['engine'] == 'pdo_sqlite') { $chunks = array_chunk($fullComments, 1); } else { $chunks = array_chunk($fullComments, 100); } # else foreach($chunks as $fullComments) { $insertArray = array(); foreach($fullComments as $comment) { # Kap de verschillende strings af op een maximum van # de datastructuur, de unique keys kappen we expres niet af $comment['fromhdr'] = substr($comment['fromhdr'], 0, 127); $insertArray[] = vsprintf("('%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s')", Array($this->safe($comment['messageid']), $this->safe($comment['fromhdr']), $this->safe($comment['stamp']), $this->safe($comment['user-signature']), $this->safe(serialize($comment['user-key'])), $this->safe($comment['spotterid']), $this->safe(implode("\r\n", $comment['body'])), $this->bool2dt($comment['verified']), $this->safe($comment['user-avatar']))); } # foreach # Actually insert the batch $this->_conn->modify("INSERT INTO commentsfull(messageid, fromhdr, stamp, usersignature, userkey, spotterid, body, verified, avatar) VALUES " . implode(',', $insertArray), array()); } # foreach $this->commitTransaction(); } # addFullComments /* * Insert addReportRef, * messageid is het werkelijke commentaar id * nntpref is de id van de spot */ function addReportRefs($reportList) { $this->beginTransaction(); # Databases can have a maximum length of statements, so we # split the amount of spots in chunks of 100 if ($this->_dbsettings['engine'] == 'pdo_sqlite') { $chunks = array_chunk($reportList, 1); } else { $chunks = array_chunk($reportList, 100); } # else foreach($chunks as $reportList) { $insertArray = array(); foreach($reportList as $report) { $insertArray[] = vsprintf("('%s', '%s', '%s', '%s')", Array($this->safe($report['messageid']), $this->safe($report['fromhdr']), $this->safe($report['keyword']), $this->safe($report['nntpref']))); } # foreach # Actually insert the batch $this->_conn->modify("INSERT INTO reportsxover(messageid, fromhdr, keyword, nntpref) VALUES " . implode(',', $insertArray), array()); } # foreach $this->commitTransaction(); } # addReportRefs /* * Update een lijst van messageid's met de gemiddelde spotrating */ function updateSpotRating($spotMsgIdList) { # Geen message id's gegeven? Doe niets! if (count($spotMsgIdList) == 0) { return; } # if # bereid de lijst voor met de queries in de where $msgIdList = ''; foreach($spotMsgIdList as $spotMsgId => $v) { $msgIdList .= "'" . $this->_conn->safe($spotMsgId) . "', "; } # foreach $msgIdList = substr($msgIdList, 0, -2); # en update de spotrating $this->_conn->modify("UPDATE spots SET spotrating = (SELECT AVG(spotrating) as spotrating FROM commentsxover WHERE spots.messageid = commentsxover.nntpref AND spotrating BETWEEN 1 AND 10 GROUP BY nntpref) WHERE spots.messageid IN (" . $msgIdList . ") "); } # updateSpotRating /* * Update een lijst van messageid's met het aantal niet geverifieerde comments */ function updateSpotCommentCount($spotMsgIdList) { if (count($spotMsgIdList) == 0) { return; } # if # bereid de lijst voor met de queries in de where $msgIdList = ''; foreach($spotMsgIdList as $spotMsgId => $v) { $msgIdList .= "'" . $this->_conn->safe($spotMsgId) . "', "; } # foreach $msgIdList = substr($msgIdList, 0, -2); # en update de spotrating $this->_conn->modify("UPDATE spots SET commentcount = (SELECT COUNT(1) as commentcount FROM commentsxover WHERE spots.messageid = commentsxover.nntpref GROUP BY nntpref) WHERE spots.messageid IN (" . $msgIdList . ") "); } # updateSpotCommentCount /* * Update een lijst van messageid's met het aantal niet geverifieerde reports */ function updateSpotReportCount($spotMsgIdList) { if (count($spotMsgIdList) == 0) { return; } # if # bereid de lijst voor met de queries in de where $msgIdList = ''; foreach($spotMsgIdList as $spotMsgId => $v) { $msgIdList .= "'" . $this->_conn->safe($spotMsgId) . "', "; } # foreach $msgIdList = substr($msgIdList, 0, -2); # en update de spotrating $this->_conn->modify("UPDATE spots SET reportcount = (SELECT COUNT(1) as reportcount FROM reportsxover WHERE spots.messageid = reportsxover.nntpref GROUP BY nntpref) WHERE spots.messageid IN (" . $msgIdList . ") "); } # updateSpotReportCount /* * Vraag de volledige commentaar lijst op, gaat er van uit dat er al een commentsxover entry is */ function getCommentsFull($userId, $nntpRef) { SpotTiming::start(__FUNCTION__); # en vraag de comments daadwerkelijk op $commentList = $this->_conn->arrayQuery("SELECT c.messageid AS messageid, (f.messageid IS NOT NULL) AS havefull, f.fromhdr AS fromhdr, f.stamp AS stamp, f.usersignature AS \"user-signature\", f.userkey AS \"user-key\", f.spotterid AS spotterid, f.body AS body, f.verified AS verified, c.spotrating AS spotrating, c.moderated AS moderated, f.avatar as \"user-avatar\" FROM commentsfull f RIGHT JOIN commentsxover c on (f.messageid = c.messageid) LEFT JOIN spotteridblacklist as bl ON ((bl.spotterid = f.spotterid) AND ((bl.ouruserid = " . $this->safe( (int) $userId) . ") OR (bl.ouruserid = -1))) WHERE c.nntpref = '%s' AND (bl.spotterid IS NULL) ORDER BY c.id", array($nntpRef)); $commentListCount = count($commentList); for($i = 0; $i < $commentListCount; $i++) { if ($commentList[$i]['havefull']) { $commentList[$i]['user-key'] = unserialize($commentList[$i]['user-key']); $commentList[$i]['body'] = explode("\r\n", $commentList[$i]['body']); } # if } # for SpotTiming::stop(__FUNCTION__); return $commentList; } # getCommentsFull /* * Geeft huidig database schema versie nummer terug */ function getSchemaVer() { return $this->_conn->singleQuery("SELECT value FROM settings WHERE name = 'schemaversion'"); } # getSchemaVer /* * Removes a comment from the database */ function removeComment($msgId) { $this->_conn->modify("DELETE FROM commentsfull WHERE messageid = '%s'", Array($msgId)); $this->_conn->modify("DELETE FROM commentsxover WHERE messageid = '%s'", Array($msgId)); } # removeComment /* * Verwijder een spot uit de db */ function deleteSpot($msgId) { switch ($this->_dbsettings['engine']) { case 'pdo_pgsql' : case 'pdo_sqlite' : { $this->_conn->modify("DELETE FROM spots WHERE messageid = '%s'", Array($msgId)); $this->_conn->modify("DELETE FROM spotsfull WHERE messageid = '%s'", Array($msgId)); $this->_conn->modify("DELETE FROM commentsfull WHERE messageid IN (SELECT messageid FROM commentsxover WHERE nntpref= '%s')", Array($msgId)); $this->_conn->modify("DELETE FROM commentsxover WHERE nntpref = '%s'", Array($msgId)); $this->_conn->modify("DELETE FROM spotstatelist WHERE messageid = '%s'", Array($msgId)); $this->_conn->modify("DELETE FROM reportsxover WHERE nntpref = '%s'", Array($msgId)); $this->_conn->modify("DELETE FROM reportsposted WHERE inreplyto = '%s'", Array($msgId)); $this->_conn->modify("DELETE FROM cache WHERE resourceid = '%s'", Array($msgId)); break; } # pdo_sqlite default : { $this->_conn->modify("DELETE FROM spots, spotsfull, commentsxover, reportsxover, spotstatelist, reportsposted, cache USING spots LEFT JOIN spotsfull ON spots.messageid=spotsfull.messageid LEFT JOIN commentsxover ON spots.messageid=commentsxover.nntpref LEFT JOIN reportsxover ON spots.messageid=reportsxover.nntpref LEFT JOIN spotstatelist ON spots.messageid=spotstatelist.messageid LEFT JOIN reportsposted ON spots.messageid=reportsposted.inreplyto LEFT JOIN cache ON spots.messageid=cache.resourceid WHERE spots.messageid = '%s'", Array($msgId)); } # default } # switch } # deleteSpot /* * Markeer een spot in de db moderated */ function markSpotModerated($msgId) { $this->_conn->modify("UPDATE spots SET moderated = '%s' WHERE messageid = '%s'", Array($this->bool2dt(true), $msgId)); } # markSpotModerated /* * Markeer een comment in de db moderated */ function markCommentModerated($msgId) { $this->_conn->modify("UPDATE commentsxover SET moderated = '%s' WHERE messageid = '%s'", Array($this->bool2dt(true), $msgId)); } # markCommentModerated /* * Verwijder oude spots uit de db */ function deleteSpotsRetention($retention) { $retention = $retention * 24 * 60 * 60; // omzetten in seconden switch ($this->_dbsettings['engine']) { case 'pdo_pgsql' : case 'pdo_sqlite': { $this->_conn->modify("DELETE FROM spots WHERE spots.stamp < " . (time() - $retention) ); $this->_conn->modify("DELETE FROM spotsfull WHERE spotsfull.messageid not in (SELECT messageid FROM spots)") ; $this->_conn->modify("DELETE FROM commentsfull WHERE messageid IN (SELECT messageid FROM commentsxover WHERE commentsxover.nntpref not in (SELECT messageid FROM spots))") ; $this->_conn->modify("DELETE FROM commentsxover WHERE commentsxover.nntpref not in (SELECT messageid FROM spots)") ; $this->_conn->modify("DELETE FROM reportsxover WHERE reporsxover.nntpref not in (SELECT messageid FROM spots)") ; $this->_conn->modify("DELETE FROM spotstatelist WHERE spotstatelist.messageid not in (SELECT messageid FROM spots)") ; $this->_conn->modify("DELETE FROM reportsposted WHERE reportsposted.inreplyto not in (SELECT messageid FROM spots)") ; $this->_conn->modify("DELETE FROM cache WHERE (cache.cachetype = %d OR cache.cachetype = %d) AND cache.resourceid not in (SELECT messageid FROM spots)", Array(SpotCache::SpotImage, SpotCache::SpotNzb)) ; break; } # pdo_sqlite default : { $this->_conn->modify("DELETE FROM spots, spotsfull, commentsxover, reportsxover, spotstatelist, reportsposted, cache USING spots LEFT JOIN spotsfull ON spots.messageid=spotsfull.messageid LEFT JOIN commentsxover ON spots.messageid=commentsxover.nntpref LEFT JOIN reportsxover ON spots.messageid=reportsxover.nntpref LEFT JOIN spotstatelist ON spots.messageid=spotstatelist.messageid LEFT JOIN reportsposted ON spots.messageid=reportsposted.inreplyto LEFT JOIN cache ON spots.messageid=cache.resourceid WHERE spots.stamp < " . (time() - $retention) ); } # default } # switch } # deleteSpotsRetention /* * Voeg een reeks met spots toe aan de database */ function addSpots($spots, $fullSpots = array()) { $this->beginTransaction(); # Databases can have a maximum length of statements, so we # split the amount of spots in chunks of 100 if ($this->_dbsettings['engine'] == 'pdo_sqlite') { $chunks = array_chunk($spots, 1); } else { $chunks = array_chunk($spots, 100); } # else foreach($chunks as $spots) { $insertArray = array(); foreach($spots as $spot) { # we checken hier handmatig of filesize wel numeriek is, dit is omdat printen met %d in sommige PHP # versies een verkeerde afronding geeft bij >32bits getallen. if (!is_numeric($spot['filesize'])) { $spot['filesize'] = 0; } # if # Kap de verschillende strings af op een maximum van # de datastructuur, de unique keys kappen we expres niet af $spot['poster'] = substr($spot['poster'], 0, 127); $spot['title'] = substr($spot['title'], 0, 127); $spot['tag'] = substr($spot['tag'], 0, 127); $spot['subcata'] = substr($spot['subcata'], 0, 63); $spot['subcatb'] = substr($spot['subcatb'], 0, 63); $spot['subcatc'] = substr($spot['subcatc'], 0, 63); $spot['subcatd'] = substr($spot['subcatd'], 0, 63); # Kap de verschillende strings af op een maximum van # de datastructuur, de unique keys en de RSA keys en dergeijke # kappen we expres niet af $spot['spotterid'] = substr($spot['spotterid'], 0, 31); $insertArray[] = vsprintf("('%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s')", Array($this->safe($spot['messageid']), $this->safe($spot['poster']), $this->safe($spot['title']), $this->safe($spot['tag']), $this->safe((int) $spot['category']), $this->safe($spot['subcata']), $this->safe($spot['subcatb']), $this->safe($spot['subcatc']), $this->safe($spot['subcatd']), $this->safe($spot['subcatz']), (int) $this->safe($spot['stamp']), (int) $this->safe(($spot['stamp'] * -1)), $this->safe($spot['filesize']), $this->safe($spot['spotterid']))); # Filesize mag niet naar int gecast worden, dan heb je 2GB limiet } # foreach # Actually insert the batch if (!empty($insertArray)) { $this->_conn->modify("INSERT INTO spots(messageid, poster, title, tag, category, subcata, subcatb, subcatc, subcatd, subcatz, stamp, reversestamp, filesize, spotterid) VALUES " . implode(',', $insertArray), array()); } # if } # foreach $this->commitTransaction(); if (!empty($fullSpots)) { $this->addFullSpots($fullSpots); } # if } # addSpot() /* * Voeg enkel de full spot toe aan de database, niet gebruiken zonder dat er een entry in 'spots' staat * want dan komt deze spot niet in het overzicht te staan. */ function addFullSpots($fullSpots) { $this->beginTransaction(); # Databases can have a maximum length of statements, so we # split the amount of spots in chunks of 100 if ($this->_dbsettings['engine'] == 'pdo_sqlite') { $chunks = array_chunk($fullSpots, 1); } else { $chunks = array_chunk($fullSpots, 100); } # else foreach($chunks as $fullSpots) { $insertArray = array(); # en voeg het aan de database toe foreach($fullSpots as $fullSpot) { $insertArray[] = vsprintf("('%s', '%s', '%s', '%s', '%s', '%s')", Array($this->safe($fullSpot['messageid']), $this->bool2dt($fullSpot['verified']), $this->safe($fullSpot['user-signature']), $this->safe(base64_encode(serialize($fullSpot['user-key']))), $this->safe($fullSpot['xml-signature']), $this->safe($fullSpot['fullxml']))); } # foreach # Actually insert the batch $this->_conn->modify("INSERT INTO spotsfull(messageid, verified, usersignature, userkey, xmlsignature, fullxml) VALUES " . implode(',', $insertArray), array()); } # foreach $this->commitTransaction(); } # addFullSpot function addToSpotStateList($list, $messageId, $ourUserId, $stamp='') { SpotTiming::start(__FUNCTION__); $verifiedList = $this->verifyListType($list); if (empty($stamp)) { $stamp = time(); } switch ($this->_dbsettings['engine']) { case 'pdo_mysql' : case 'mysql' : { $this->_conn->modify("INSERT INTO spotstatelist (messageid, ouruserid, " . $verifiedList . ") VALUES ('%s', %d, %d) ON DUPLICATE KEY UPDATE " . $verifiedList . " = %d", Array($messageId, (int) $ourUserId, $stamp, $stamp)); break; } # mysql default : { $this->_conn->modify("UPDATE spotstatelist SET " . $verifiedList . " = %d WHERE messageid = '%s' AND ouruserid = %d", array($stamp, $messageId, $ourUserId)); if ($this->_conn->rows() == 0) { $this->_conn->modify("INSERT INTO spotstatelist (messageid, ouruserid, " . $verifiedList . ") VALUES ('%s', %d, %d)", Array($messageId, (int) $ourUserId, $stamp)); } # if } # default } # switch SpotTiming::stop(__FUNCTION__, array($list, $messageId, $ourUserId, $stamp)); } # addToSpotStateList function clearSpotStateList($list, $ourUserId) { SpotTiming::start(__FUNCTION__); $verifiedList = $this->verifyListType($list); $this->_conn->modify("UPDATE spotstatelist SET " . $verifiedList . " = NULL WHERE ouruserid = %d", array($ourUserId)); SpotTiming::stop(__FUNCTION__, array($list, $ourUserId)); } # clearSpotStatelist function cleanSpotStateList() { $this->_conn->rawExec("DELETE FROM spotstatelist WHERE download IS NULL AND watch IS NULL AND seen IS NULL"); } # cleanSpotStateList function removeFromSpotStateList($list, $messageid, $ourUserId) { SpotTiming::start(__FUNCTION__); $verifiedList = $this->verifyListType($list); $this->_conn->modify("UPDATE spotstatelist SET " . $verifiedList . " = NULL WHERE messageid = '%s' AND ouruserid = %d LIMIT 1", Array($messageid, (int) $ourUserId)); SpotTiming::stop(__FUNCTION__, array($list, $messageid, $ourUserId)); } # removeFromSpotStateList function verifyListType($list) { switch($list) { case self::spotstate_Down : $verifiedList = 'download'; break; case self::spotstate_Watch : $verifiedList = 'watch'; break; case self::spotstate_Seen : $verifiedList = 'seen'; break; default : throw new Exception("Invalid listtype given!"); } # switch return $verifiedList; } # verifyListType /* * Geeft de permissies terug van een bepaalde groep */ function getGroupPerms($groupId) { return $this->_conn->arrayQuery("SELECT permissionid, objectid, deny FROM grouppermissions WHERE groupid = %d", Array($groupId)); } # getgroupPerms /* * Geeft permissies terug welke user heeft, automatisch in het formaat zoals * SpotSecurity dat heeft (maw - dat de rechtencheck een simpele 'isset' is om * overhead te voorkomen */ function getPermissions($userId) { $permList = array(); $tmpList = $this->_conn->arrayQuery('SELECT permissionid, objectid, deny FROM grouppermissions WHERE groupid IN (SELECT groupid FROM usergroups WHERE userid = %d ORDER BY prio)', Array($userId)); foreach($tmpList as $perm) { # Voeg dit permissionid toe aan de lijst met permissies if (!isset($permList[$perm['permissionid']])) { $permList[$perm['permissionid']] = array(); } # if $permList[$perm['permissionid']][$perm['objectid']] = !(boolean) $perm['deny']; } # foreach return $permList; } # getPermissions /* * Geeft alle gedefinieerde groepen terug */ function getGroupList($userId) { if ($userId == null) { return $this->_conn->arrayQuery("SELECT id,name,0 as \"ismember\" FROM securitygroups"); } else { return $this->_conn->arrayQuery("SELECT sg.id,name,ug.userid IS NOT NULL as \"ismember\" FROM securitygroups sg LEFT JOIN usergroups ug ON (sg.id = ug.groupid) AND (ug.userid = %d)", Array($userId)); } # if } # getGroupList /* * Verwijdert een permissie uit een security group */ function removePermFromSecGroup($groupId, $perm) { $this->_conn->modify("DELETE FROM grouppermissions WHERE (groupid = %d) AND (permissionid = %d) AND (objectid = '%s')", Array($groupId, $perm['permissionid'], $perm['objectid'])); } # removePermFromSecGroup /* * Zet een permissie op deny in een security group */ function setDenyForPermFromSecGroup($groupId, $perm) { $this->_conn->modify("UPDATE grouppermissions SET deny = '%s' WHERE (groupid = %d) AND (permissionid = %d) AND (objectid = '%s')", Array($this->bool2dt($perm['deny']), $groupId, $perm['permissionid'], $perm['objectid'])); } # removePermFromSecGroup /* * Voegt een permissie aan een security group toe */ function addPermToSecGroup($groupId, $perm) { $this->_conn->modify("INSERT INTO grouppermissions(groupid,permissionid,objectid) VALUES (%d, %d, '%s')", Array($groupId, $perm['permissionid'], $perm['objectid'])); } # addPermToSecGroup /* * Geef een specifieke security group terug */ function getSecurityGroup($groupId) { return $this->_conn->arrayQuery("SELECT id,name FROM securitygroups WHERE id = %d", Array($groupId)); } # getSecurityGroup /* * Geef een specifieke security group terug */ function setSecurityGroup($group) { $this->_conn->modify("UPDATE securitygroups SET name = '%s' WHERE id = %d", Array($group['name'], $group['id'])); } # setSecurityGroup /* * Geef een specifieke security group terug */ function addSecurityGroup($group) { $this->_conn->modify("INSERT INTO securitygroups(name) VALUES ('%s')", Array($group['name'])); } # addSecurityGroup /* * Geef een specifieke security group terug */ function removeSecurityGroup($group) { $this->_conn->modify("DELETE FROM securitygroups WHERE id = %d", Array($group['id'])); } # removeSecurityGroup /* * Wijzigt group membership van een user */ function setUserGroupList($userId, $groupList) { # We wissen eerst huidige group membership $this->_conn->modify("DELETE FROM usergroups WHERE userid = %d", array($userId)); foreach($groupList as $groupInfo) { $this->_conn->modify("INSERT INTO usergroups(userid,groupid,prio) VALUES(%d, %d, %d)", Array($userId, $groupInfo['groupid'], $groupInfo['prio'])); } # foreach } # setUserGroupList /* * Voegt een nieuwe notificatie toe */ function addNewNotification($userId, $objectId, $type, $title, $body) { $this->_conn->modify("INSERT INTO notifications(userid,stamp,objectid,type,title,body,sent) VALUES(%d, %d, '%s', '%s', '%s', '%s', '%s')", Array($userId, (int) time(), $objectId, $type, $title, $body, $this->bool2dt(false))); } # addNewNotification /* * Haalt niet-verzonden notificaties op van een user */ function getUnsentNotifications($userId) { return $this->_conn->arrayQuery("SELECT id,userid,objectid,type,title,body FROM notifications WHERE userid = %d AND NOT SENT;", Array($userId)); } # getUnsentNotifications /* * Een notificatie updaten */ function updateNotification($msg) { $this->_conn->modify("UPDATE notifications SET title = '%s', body = '%s', sent = '%s' WHERE id = %d", Array($msg['title'], $msg['body'], $this->bool2dt($msg['sent']), $msg['id'])); } // updateNotification /* * Voegt een spotterid toe aan de blacklist */ function addSpotterToBlacklist($spotterId, $ourUserId, $origin) { $this->_conn->modify("INSERT INTO spotteridblacklist(spotterid, origin, ouruserid) VALUES ('%s', '%s', %d)", Array($spotterId, $origin, (int) $ourUserId)); } # addSpotterToBlackList /* * Removes a specific spotter from the blacklis */ function removeSpotterFromBlacklist($spotterId, $ourUserId) { $this->_conn->modify("DELETE FROM spotteridblacklist WHERE ouruserid = %d AND spotterid = '%s'", Array((int) $ourUserId, $spotterId)); } # addSpotterToBlackList /* * Geeft alle blacklisted spotterid's terug */ function getSpotterBlacklist($ourUserId) { return $this->_conn->arrayQuery("SELECT spotterid, origin, ouruserid FROM spotteridblacklist WHERE ouruserid = %d", Array((int) $ourUserId)); } # getSpotterBlacklist /* * Returns one specific blacklisted record for a given spotterid */ function getBlacklistForSpotterId($userId, $spotterId) { $tmp = $this->_conn->arrayQuery("SELECT spotterid, origin, ouruserid FROM spotteridblacklist WHERE ouruserid = %d and spotterid = '%s'", Array($userId, $spotterId)); if (!empty($tmp)) { return $tmp[0]; } else { return false; } # else } # getBlacklistForSpotterId /* * Geeft alle blacklisted spotterid's terug */ function isSpotterBlacklisted($spotterId, $ourUserId) { $blacklistResult = $this->_conn->arrayQuery("SELECT spotterid FROM spotteridblacklist WHERE ((ouruserid = %d) OR (ouruserid = -1)) AND (spotterid = '%s')", Array((int) $ourUserId, $spotterId)); return (!empty($blacklistResult)); } # getSpotterBlacklist /* * Verwijder een filter en de children toe (recursive) */ function deleteFilter($userId, $filterId, $filterType) { $filterList = $this->getFilterList($userId, $filterType); foreach($filterList as $filter) { if ($filter['id'] == $filterId) { foreach($filter['children'] as $child) { $this->deleteFilter($userId, $child['id'], $filterType); } # foreach } # if $this->_conn->modify("DELETE FROM filters WHERE userid = %d AND id = %d", Array($userId, $filterId)); } # foreach } # deleteFilter /* * Voegt een filter en de children toe (recursive) */ function addFilter($userId, $filter) { $this->_conn->modify("INSERT INTO filters(userid, filtertype, title, icon, torder, tparent, tree, valuelist, sorton, sortorder) VALUES(%d, '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s')", Array((int) $userId, $filter['filtertype'], $filter['title'], $filter['icon'], (int) $filter['torder'], (int) $filter['tparent'], $filter['tree'], implode('&', $filter['valuelist']), $filter['sorton'], $filter['sortorder'])); $parentId = $this->_conn->lastInsertId('filters'); foreach($filter['children'] as $tmpFilter) { $tmpFilter['tparent'] = $parentId; $this->addFilter($userId, $tmpFilter); } # foreach } # addFilter /* * Copieert de filterlijst van een user naar een andere user */ function copyFilterList($srcId, $dstId) { $filterList = $this->getFilterList($srcId, ''); foreach($filterList as $filterItems) { $this->addFilter($dstId, $filterItems); } # foreach } # copyFilterList /* * Verwijdert alle ingestelde filters voor een user */ function removeAllFilters($userId) { $this->_conn->modify("DELETE FROM filters WHERE userid = %d", Array((int) $userId)); } # removeAllfilters /* * Get a specific filter */ function getFilter($userId, $filterId) { /* Haal de lijst met filter values op */ $tmpResult = $this->_conn->arrayQuery("SELECT id, userid, filtertype, title, icon, torder, tparent, tree, valuelist, sorton, sortorder FROM filters WHERE userid = %d AND id = %d", Array((int) $userId, (int) $filterId)); if (!empty($tmpResult)) { return $tmpResult[0]; } else { return false; } # else } # getFilter /* * Get a specific index filter */ function getUserIndexFilter($userId) { /* Haal de lijst met filter values op */ $tmpResult = $this->_conn->arrayQuery("SELECT id, userid, filtertype, title, icon, torder, tparent, tree, valuelist, sorton, sortorder FROM filters WHERE userid = %d AND filtertype = 'index_filter'", Array((int) $userId)); if (!empty($tmpResult)) { return $tmpResult[0]; } else { return false; } # else } # getUserIndexFilter /* * Get a specific filter */ function updateFilter($userId, $filter) { /* Haal de lijst met filter values op */ $tmpResult = $this->_conn->modify("UPDATE filters SET title = '%s', icon = '%s', torder = %d, tparent = %d WHERE userid = %d AND id = %d", Array($filter['title'], $filter['icon'], (int) $filter['torder'], (int) $filter['tparent'], (int) $userId, (int) $filter['id'])); } # updateFilter /* * Haalt de filterlijst op als een platte lijst */ function getPlainFilterList($userId, $filterType) { /* willen we een specifiek soort filter hebben? */ if (empty($filterType)) { $filterTypeFilter = ''; } else { $filterTypeFilter = " AND filtertype = 'filter'"; } # else /* Haal de lijst met filter values op */ return $this->_conn->arrayQuery("SELECT id, userid, filtertype, title, icon, torder, tparent, tree, valuelist, sorton, sortorder FROM filters WHERE userid = %d " . $filterTypeFilter . " ORDER BY tparent,torder", /* was: id, tparent, torder */ Array($userId)); } # getPlainFilterList /* * Haalt de filter lijst op en formatteert die in een boom */ function getFilterList($userId, $filterType) { $tmpResult = $this->getPlainFilterList($userId, $filterType); $idMapping = array(); foreach($tmpResult as &$tmp) { $idMapping[$tmp['id']] =& $tmp; } # foreach /* Hier zetten we het om naar een daadwerkelijke boom */ $tree = array(); foreach($tmpResult as &$filter) { if (!isset($filter['children'])) { $filter['children'] = array(); } # if # de filter waardes zijn URL encoded opgeslagen # en we gebruiken de & om individuele filterwaardes # te onderscheiden $filter['valuelist'] = explode('&', $filter['valuelist']); if ($filter['tparent'] == 0) { $tree[$filter['id']] =& $filter; } else { $idMapping[$filter['tparent']]['children'][] =& $filter; } # else } # foreach return $tree; } # getFilterList /* * Returns a list of all unique filter combinations */ function getUniqueFilterCombinations() { return $this->_conn->arrayQuery("SELECT tree,valuelist FROM filters GROUP BY tree,valuelist ORDER BY tree,valuelist"); } # getUniqueFilterCombinations /* * Add a filter count for a specific SHA1 hash * of a filter for this specific user */ function setCachedFilterCount($userId, $filterHashes) { $maxSpotStamp = $this->getMaxMessageTime(); foreach($filterHashes as $filterHash => $filterCount) { /* Remove any existing cached filtercount for this user */ $this->_conn->modify("DELETE FROM filtercounts WHERE (userid = %d) AND (filterhash = '%s')", Array((int) $userId, $filterHash)); /* and insert our new filtercount hash */ $this->_conn->modify("INSERT INTO filtercounts(userid, filterhash, currentspotcount, lastvisitspotcount, lastupdate) VALUES(%d, '%s', %d, %d, %d)", Array((int) $userId, $filterHash, $filterCount['currentspotcount'], $filterCount['lastvisitspotcount'], $maxSpotStamp )); } # foreach } # setCachedFilterCount /* * Add a filter count for a specific SHA1 hash * of a filter for this specific user */ function getNewCountForFilters($userId) { $filterHashes = array(); $tmp = $this->_conn->arrayQuery("SELECT f.filterhash AS filterhash, f.currentspotcount AS currentspotcount, f.lastvisitspotcount AS lastvisitspotcount, f.lastupdate AS lastupdate, t.currentspotcount - f.lastvisitspotcount AS newspotcount FROM filtercounts f INNER JOIN filtercounts t ON (t.filterhash = f.filterhash) WHERE t.userid = -1 AND f.userid = %d", Array((int) $userId) ); foreach($tmp as $cachedItem) { $filterHashes[$cachedItem['filterhash']] = array('currentspotcount' => $cachedItem['currentspotcount'], 'lastvisitspotcount' => $cachedItem['lastvisitspotcount'], 'newspotcount' => $cachedItem['newspotcount'], 'lastupdate' => $cachedItem['lastupdate']); } # foreach return $filterHashes; } # getNewCountForFilters /* * Makes sure all registered users have at least counts * for all existing filters. */ function createFilterCountsForEveryone() { $userIdList = $this->_conn->arrayQuery('SELECT id FROM users WHERE id <> -1'); foreach($userIdList as $user) { $userId = $user['id']; /* We can assume userid -1 (baseline) has all the filters which exist */ $filterList = $this->getPlainFilterList($userId, ''); $cachedList = $this->getCachedFilterCount($userId); /* We add a dummy entry for 'all new spots' */ $filterList[] = array('id' => 9999, 'userid' => $userId, 'filtertype' => 'dummyfilter', 'title' => 'NewSpots', 'icon' => '', 'torder' => 0, 'tparent' => 0, 'tree' => '', 'valuelist' => 'New:0', 'sorton' => '', 'sortorder' => ''); foreach($filterList as $filter) { $filterHash = sha1($filter['tree'] . '|' . urldecode($filter['valuelist'])); # Do we have a cache entry already for this filter? if (!isset($cachedList[$filterHash])) { /* * Create the cached count filter */ $filter['currentspotcount'] = 0; $filter['lastvisitspotcount'] = 0; $this->setCachedFilterCount($userId, array($filterHash => $filter)); } # if } # foreach } # foreach } # createFilterCountsForEveryone /* * Retrieves the filtercount for a specific userid */ function getCachedFilterCount($userId) { $filterHashes = array(); $tmp = $this->_conn->arrayQuery("SELECT filterhash, currentspotcount, lastvisitspotcount, lastupdate FROM filtercounts WHERE userid = %d", Array( (int) $userId) ); foreach($tmp as $cachedItem) { $filterHashes[$cachedItem['filterhash']] = array('currentspotcount' => $cachedItem['currentspotcount'], 'lastvisitspotcount' => $cachedItem['lastvisitspotcount'], 'lastupdate' => $cachedItem['lastupdate']); } # foreach return $filterHashes; } # getCachedFilterCount /* * Resets the unread count for a specific user */ function resetFilterCountForUser($userId) { switch ($this->_dbsettings['engine']) { case 'pdo_sqlite' : { $filterList = $this->_conn->arrayQuery("SELECT currentspotcount, filterhash FROM filtercounts WHERE userid = -1", array()); foreach($filterList as $filter) { $this->_conn->modify("UPDATE filtercounts SET lastvisitspotcount = currentspotcount, currentspotcount = %d WHERE (filterhash = '%s') AND (userid = %d)", Array((int) $filter['currentspotcount'], $filter['filterhash'], (int) $userId)); } # foreach break; } # sqlite case 'pdo_pgsql' : { $this->_conn->modify("UPDATE filtercounts f SET f.lastvisitspotcount = f.currentspotcount, f.currentspotcount = t.currentspotcount FROM filtercounts t WHERE (f.filterhash = t.filterhash) AND (t.userid = -1) AND (f.userid = %d)", Array((int) $userId) ); break; } # pgsql default : { $this->_conn->modify("UPDATE filtercounts f, filtercounts t SET f.lastvisitspotcount = f.currentspotcount, f.currentspotcount = t.currentspotcount WHERE (f.filterhash = t.filterhash) AND (t.userid = -1) AND (f.userid = %d)", Array((int) $userId) ); } # default } # switch } # resetFilterCountForUser /* * Updates the last filtercounts for sessions which are active at the moment */ function updateCurrentFilterCounts() { switch ($this->_dbsettings['engine']) { case 'pdo_pgsql' : { /* * Update the current filter counts if the session * is still active */ $this->_conn->modify("UPDATE filtercounts f SET f.currentspotcount = t.currentspotcount, f.lastupdate = t.lastupdate FROM filtercounts t WHERE (f.filterhash = t.filterhash) AND (t.userid = -1) AND (f.userid IN (SELECT userid FROM sessions WHERE lasthit > f.lastupdate GROUP BY userid ))", array()); /* * Sometimes retrieve removes some sports, make sure * we do not get confusing results */ $this->_conn->modify("UPDATE filtercounts f SET f.lastvisitspotcount = t.currentspotcount FROM filtercounts t WHERE (f.filterhash = t.filterhash) AND (f.lastvisitspotcount > t.currentspotcount AND (t.userid = -1))"); break; } # pgsql case 'pdo_sqlite' : { /* * Update the current filter counts if the session * is still active */ $filterList = $this->_conn->arrayQuery("SELECT currentspotcount, lastupdate, filterhash FROM filtercounts WHERE userid = -1", array()); foreach($filterList as $filter) { $this->_conn->modify("UPDATE filtercounts SET currentspotcount = %d, lastupdate = %d WHERE (filterhash = '%s') AND (userid IN (SELECT userid FROM sessions WHERE lasthit > f.lastupdate GROUP BY userid ))", Array((int) $filter['currentspotcount'], (int) $filter['lastupdate'], $filter['filterhash'], (int) $userId)); } # foreach break; } # pdo_sqlite default : { /* * We do this in two parts because MySQL seems to fall over * when we use a subquery */ $sessionList = $this->_conn->arrayQuery("SELECT s.userid FROM sessions s INNER JOIN filtercounts f ON (f.userid = s.userid) WHERE lasthit > f.lastupdate GROUP BY s.userid", array()); # bereid de lijst voor met de queries in de where $userIdList = ''; foreach($sessionList as $session) { $userIdList .= (int) $this->_conn->safe($session['userid']) . ", "; } # foreach $userIdList = substr($userIdList, 0, -2); /* * Update the current filter counts if the session * is still active */ if (!empty($userIdList)) { $this->_conn->modify("UPDATE filtercounts f, filtercounts t SET f.currentspotcount = t.currentspotcount, f.lastupdate = t.lastupdate WHERE (f.filterhash = t.filterhash) AND (t.userid = -1) AND (f.userid IN (" . $userIdList . "))"); } # if /* * Sometimes retrieve removes some sports, make sure * we do not get confusing results */ $this->_conn->modify("UPDATE filtercounts f, filtercounts t SET f.lastvisitspotcount = t.currentspotcount WHERE (f.filterhash = t.filterhash) AND (f.lastvisitspotcount > t.currentspotcount) AND (t.userid = -1)"); } # default } # switch } # updateCurrentFilterCounts /* * Mark all filters as read */ function markFilterCountAsSeen($userId) { switch ($this->_dbsettings['engine']) { case 'pdo_sqlite' : { $filterList = $this->_conn->arrayQuery("SELECT currentspotcount, lastupdate, filterhash FROM filtercounts WHERE userid = -1", array()); foreach($filterList as $filter) { $this->_conn->modify("UPDATE filtercounts SET lastvisitspotcount = %d, currentspotcount = %d, lastupdate = %d WHERE (filterhash = '%s') AND (userid = %d)", Array((int) $filter['currentspotcount'], (int) $filter['currentspotcount'], (int) $filter['lastupdate'], $filter['filterhash'], (int) $userId)); } # foreach break; } # pdo_sqlite case 'pdo_pgsql' : { $this->_conn->modify("UPDATE filtercounts f, filtercounts t SET f.lastvisitspotcount = t.currentspotcount, f.currentspotcount = t.currentspotcount, f.lastupdate = t.lastupdate WHERE (f.filterhash = t.filterhash) AND (t.userid = -1) AND (f.userid = %d)", Array( (int) $userId) ); break; } # pgsql default : { $this->_conn->modify("UPDATE filtercounts f, filtercounts t SET f.lastvisitspotcount = t.currentspotcount, f.currentspotcount = t.currentspotcount, f.lastupdate = t.lastupdate WHERE (f.filterhash = t.filterhash) AND (t.userid = -1) AND (f.userid = %d)", Array( (int) $userId) ); } # default } # switch } # markFilterCountAsSeen /* * Create an entry in the auditlog */ function addAuditEntry($userid, $perm, $objectid, $allowed, $ipaddr) { return $this->_conn->modify("INSERT INTO permaudit(stamp, userid, permissionid, objectid, result, ipaddr) VALUES(%d, %d, %d, '%s', '%s', '%s')", Array(time(), (int) $userid, (int) $perm, $objectid, $this->bool2dt($allowed), $ipaddr)); } # addAuditEntry function cleanCache($expireDays) { return $this->_conn->modify("DELETE FROM cache WHERE (cachetype = %d OR cachetype = %d OR cachetype = %d) AND stamp < %d", Array(SpotCache::Web, SpotCache::Statistics, SpotCache::StatisticsData,(int) time()-$expireDays*24*60*60)); } # cleanCache function isCached($resourceid, $cachetype) { $tmpResult = $this->_conn->singleQuery("SELECT resourceid FROM cache WHERE resourceid = '%s' AND cachetype = '%s'", Array($resourceid, $cachetype)); return (!empty($tmpResult)); } # isCached function getCache($resourceid, $cachetype) { switch ($this->_dbsettings['engine']) { case 'pdo_pgsql' : { $tmp = $this->_conn->arrayQuery("SELECT stamp, metadata, serialized, content FROM cache WHERE resourceid = '%s' AND cachetype = '%s'", array($resourceid, $cachetype)); if (!empty($tmp)) { $tmp[0]['content'] = stream_get_contents($tmp[0]['content']); } # if break; } # case 'pdo_pgsql' case 'mysql' : case 'pdo_mysql' : { $tmp = $this->_conn->arrayQuery("SELECT stamp, metadata, serialized, UNCOMPRESS(content) AS content FROM cache WHERE resourceid = '%s' AND cachetype = '%s'", array($resourceid, $cachetype)); break; } # mysql default : { $tmp = $this->_conn->arrayQuery("SELECT stamp, metadata, serialized, content FROM cache WHERE resourceid = '%s' AND cachetype = '%s'", array($resourceid, $cachetype)); } # default } # switch if (!empty($tmp)) { if ($tmp[0]['serialized'] == 1) { $tmp[0]['content'] = unserialize($tmp[0]['content']); } # if $tmp[0]['metadata'] = unserialize($tmp[0]['metadata']); return $tmp[0]; } # if return false; } # getCache function updateCacheStamp($resourceid, $cachetype) { $this->_conn->exec("UPDATE cache SET stamp = %d WHERE resourceid = '%s' AND cachetype = '%s'", Array(time(), $resourceid, $cachetype)); } # updateCacheStamp function saveCache($resourceid, $cachetype, $metadata, $content) { if (is_array($content)) { $serialize = true; $content = serialize($content); } else { $serialize = false; } # else if ($metadata) { $metadata = serialize($metadata); } # if if ($this->getMaxPacketsize() > 0 && (strlen($content)*1.15)+115 > $this->getMaxPacketSize()) { return; } # if switch ($this->_dbsettings['engine']) { case 'pdo_pgsql' : { $this->_conn->exec("UPDATE cache SET stamp = %d, metadata = '%s', serialized = '%s', content = '%b' WHERE resourceid = '%s' AND cachetype = '%s'", Array(time(), $metadata, $this->bool2dt($serialize), $content, $resourceid, $cachetype)); if ($this->_conn->rows() == 0) { $this->_conn->modify("INSERT INTO cache(resourceid,cachetype,stamp,metadata,serialized,content) VALUES ('%s', '%s', %d, '%s', '%s', '%b')", Array($resourceid, $cachetype, time(), $metadata, $this->bool2dt($serialize), $content)); } # if break; } # pgsql case 'mysql' : case 'pdo_mysql' : { $this->_conn->exec("UPDATE cache SET stamp = %d, metadata = '%s', serialized = '%s', content = COMPRESS('%s') WHERE resourceid = '%s' AND cachetype = '%s'", Array(time(), $metadata, $this->bool2dt($serialize), $content, $resourceid, $cachetype)); if ($this->_conn->rows() == 0) { $this->_conn->modify("INSERT INTO cache(resourceid,cachetype,stamp,metadata,serialized,content) VALUES ('%s', '%s', %d, '%s', '%s', COMPRESS('%s'))", Array($resourceid, $cachetype, time(), $metadata, $this->bool2dt($serialize), $content)); } # if break; } # mysql default : { $this->_conn->exec("UPDATE cache SET stamp = %d, metadata = '%s', serialized = '%s', content = '%s' WHERE resourceid = '%s' AND cachetype = '%s'", Array(time(), $metadata, $this->bool2dt($serialize), $content, $resourceid, $cachetype)); if ($this->_conn->rows() == 0) { $this->_conn->modify("INSERT INTO cache(resourceid,cachetype,stamp,metadata,serialized,content) VALUES ('%s', '%s', %d, '%s', '%s', '%s')", Array($resourceid, $cachetype, time(), $metadata, $this->bool2dt($serialize), $content)); } # if } # default } # switch } # saveCache /* * Updates a users' setting with an base64 encoded image */ function setUserAvatar($userId, $imageEncoded) { $this->_conn->modify("UPDATE usersettings SET avatar = '%s' WHERE userid = %d", Array( $imageEncoded, (int) $userId)); } # setUserAvatar function beginTransaction() { $this->_conn->beginTransaction(); } # beginTransaction function abortTransaction() { $this->_conn->rollback(); } # abortTransaction function commitTransaction() { $this->_conn->commit(); } # commitTransaction function safe($q) { return $this->_conn->safe($q); } # safe /* * Converts a boolean value to a string * for usage by the database */ function bool2dt($b) { return $this->_conn->bool2dt($b); } # bool2dt function removeOldBlackList($blacklistUrl) { $this->_conn->modify("DELETE FROM spotteridblacklist WHERE (ouruserid = -1) AND (origin = 'external')"); $this->_conn->modify("DELETE FROM cache WHERE (resourceid = '%s') AND (cachetype = '%s')", Array(md5($blacklistUrl), SpotCache::Web)); } # removeOldBlackList function updateExternalBlacklist($newblacklist) { $updatelist = array(); $updskipped = 0; $countnewblacklistspotterid = 0; $countdelblacklistspotterid = 0; /* Haal de oude blacklist op*/ $oldblacklist = $this->_conn->arrayQuery("SELECT spotterid FROM spotteridblacklist WHERE ouruserid = -1 AND origin = 'external'"); foreach ($oldblacklist as $obl) { $updatelist[$obl['spotterid']] = 2; # 'oude' spotterid eerst op verwijderen zetten. } /* verwerk de nieuwe blacklist */ foreach ($newblacklist as $nbl) { $nbl = trim($nbl); # Enters en eventuele spaties wegfilteren if ((strlen($nbl) >= 3) && (strlen($nbl) <= 6)) { # de lengte van een spotterid is tussen 3 en 6 karakters groot (tot op heden) if (empty($updatelist[$nbl])) { $updatelist[$nbl] = 1; # nieuwe spoterids toevoegen } elseif ($updatelist[$nbl] == 2) { $updatelist[$nbl] = 3; # spotterid staat nog steeds op de blacklist, niet verwijderen. } else { $updskipped++; # dubbel spotterid in blacklist.txt. } } else { $updskipped++; # er is iets mis met het spotterid (bijvoorbeeld een lege regel in blacklist.txt) } } $updblacklist = array_keys($updatelist); foreach ($updblacklist as $updl) { if ($updatelist[$updl] == 1) { # voeg nieuwe spotterid's toe aan de blacklist $countnewblacklistspotterid++; $this->_conn->modify("INSERT INTO spotteridblacklist (spotterid,ouruserid,origin) VALUES ('%s','-1','external')", Array($updl)); } elseif ($updatelist[$updl] == 2) { # verwijder spotterid's die niet meer op de blacklist staan $countdelblacklistspotterid++; $this->_conn->modify("DELETE FROM spotteridblacklist WHERE (spotterid = '%s') AND (ouruserid = -1) AND (origin = 'external')", Array($updl)); } } return array('added' => $countnewblacklistspotterid,'removed' => $countdelblacklistspotterid,'skipped' => $updskipped); } # updateExternalBlacklist } # class db debian/db-update/v20111210/lib/SpotSeclibToOpenSsl.php0000644000000000000000000001266212267045571017265 0ustar _pubKeyCache[$rsaKey['modulo'] . $rsaKey['exponent']])) { $openSslPubKey = $this->_pubKeyCache[$rsaKey['modulo'] . $rsaKey['exponent']]; $verified = openssl_verify($toCheck, $signature, $openSslPubKey); } else { # Initialize the public key to verify with $pubKey['n'] = base64_decode($rsaKey['modulo']); $pubKey['e'] = base64_decode($rsaKey['exponent']); $openSslPubKey = openssl_get_publickey($this->seclibToOpenSsl($pubKey)); $verified = openssl_verify($toCheck, $signature, $openSslPubKey); # Moeten we de resource cachen ipv vrijgeven? if ($useCache) { $this->_pubKeyCache[$rsaKey['modulo'] . $rsaKey['exponent']] = $openSslPubKey; } else { openssl_free_key($openSslPubKey); } # else } # else return $verified; } # verify function _getOidElementLength($component) { # Code copied from # http://chaosinmotion.com/wiki/index.php?title=ASN.1_Library if ($component < 0) return 10; // Full 64 bits takes 10*7 bits to encode $l = 1; for ($i = 1; $i < 9; ++$i) { $l <<= 7; if ($component < $l) break; } return $i; } function _encodeObjectId($vals) { $return = array(); $return[] = 40 * $vals[0] + $vals[1]; $valCount = count($vals); for($i = 2; $i < $valCount; $i++) { # Code copied from # http://chaosinmotion.com/wiki/index.php?title=ASN.1_Library $v = $vals[$i]; $len = $this->_getOIDElementLength($v); for ($j = $len-1; $j > 0; --$j) { $m = 0x0080 | (0x007F & ($v >> ($j * 7))); $return[] = (int) $m; } $return[] = (int)(0x007F & $v); } return $return; } # _encodeObjectId function seclibToOpenSsl($pubKey) { /* * Structuur van de OpenSSL publickey is als volgt: * * - Sequence * +- Sequence * ++- Object identifier die de RSA key weergeeft (1.2.840.113549.1.1.1) * ++- NULL * +- Bit String * ++- Sequence * +++- Integer * +++- Integer * * Dit willen we nabootsen met deze encoding */ $publicExponent = $pubKey['e']; $modulus = $pubKey['n']; $components = array( 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus), 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent) ); /* * First encoden we de keys in een bitstring */ $encodedKeys = pack('Ca*a*a*', CRYPT_RSA_ASN1_SEQUENCE, # Sequence $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), $components['modulus'], $components['publicExponent'] ); $encodedKeys = pack('Ca*Ca*', 0x03, # 0x03 means BIT STRING $this->_encodeLength(strlen($encodedKeys) + 1), # add 1 voor de 0 unused bits 0, $encodedKeys ); /* * Nu creeeren we de type header * * We kunnen de rsaIdentifier berekenen, maar omdat dat toch nooit verandert, * zetten we de berekening klaar. * Code om te berekenen: * $rsaIdentifier = $this->_encodeObjectId(array(1,2,840,113549,1,1,1)); // Magic value of RSA * * $encryptionType = pack('Ca*', * 0x06, # ASN.1 OBJECT IDENTIFIER * $this->_encodeLength(count($rsaIdentifier)) * ); * $rsaIdentifierCount = count($rsaIdentifier); * for($i = 0; $i < $rsaIdentifierCount; $i++) { * $encryptionType .= chr($rsaIdentifier[$i]); * } # foreach * * * # de encryption type header wordt geappend met een ASN.1 NULL * $encryptionType .= pack('CC', * 0x05, # ASN.1 NULL * 0 * ); * * # en de encryptiontype pakken we in in een sequence * $encryptionType = pack('Ca*a*', * CRYPT_RSA_ASN1_SEQUENCE, # Sequence * $this->_encodeLength(strlen($encryptionType)), * $encryptionType * ); */ $encryptionType = "\x30\xd\x6\x9\x2a\x86\x48\x86\xf7\xd\x1\x1\x1\x5\x0"; # en ook dit alles pakken we in een sequence in $endResult = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, # Sequence $this->_encodeLength(15 + strlen($encodedKeys)), # 15 == strlen($encryptionType) $encryptionType . $encodedKeys ); return "-----BEGIN PUBLIC KEY-----\n" . chunk_split(base64_encode($endResult), 64) . "-----END PUBLIC KEY-----\n"; } # seclibToOpenSsl /** * * From phpSeclib library * * DER-encode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information. * * @access private * @param Integer $length * @return String */ function _encodeLength($length) { if ($length <= 0x7F) { return chr($length); } $temp = ltrim(pack('N', $length), chr(0)); return pack('Ca*', 0x80 | strlen($temp), $temp); } } # SpotSeclibToOpenSsl debian/db-update/v20111210/lib/dbstruct/0000755000000000000000000000000012267045571014521 5ustar debian/db-update/v20111210/lib/dbstruct/SpotStruct_mysql.php0000644000000000000000000002670312267045571020621 0ustar _dbcon->rawExec("ANALYZE TABLE spotstatelist"); $this->_dbcon->rawExec("ANALYZE TABLE sessions"); $this->_dbcon->rawExec("ANALYZE TABLE users"); $this->_dbcon->rawExec("ANALYZE TABLE commentsfull"); $this->_dbcon->rawExec("ANALYZE TABLE spots"); $this->_dbcon->rawExec("ANALYZE TABLE spotsfull"); $this->_dbcon->rawExec("ANALYZE TABLE commentsxover"); } # analyze /* converteert een "spotweb" datatype naar een mysql datatype */ function swDtToNative($colType) { switch(strtoupper($colType)) { case 'INTEGER' : $colType = 'int(11)'; break; case 'UNSIGNED INTEGER' : $colType = 'int(10) unsigned'; break; case 'BIGINTEGER' : $colType = 'bigint(20)'; break; case 'UNSIGNED BIGINTEGER' : $colType = 'bigint(20) unsigned'; break; case 'BOOLEAN' : $colType = 'tinyint(1)'; break; case 'MEDIUMBLOB' : $colType = 'mediumblob'; break; } # switch return $colType; } # swDtToNative /* converteert een mysql datatype naar een "spotweb" datatype */ function nativeDtToSw($colInfo) { switch(strtolower($colInfo)) { case 'int(11)' : $colInfo = 'INTEGER'; break; case 'int(10) unsigned' : $colInfo = 'UNSIGNED INTEGER'; break; case 'bigint(20)' : $colInfo = 'BIGINTEGER'; break; case 'bigint(20) unsigned' : $colInfo = 'UNSIGNED BIGINTEGER'; break; case 'tinyint(1)' : $colInfo = 'BOOLEAN'; break; case 'mediumblob' : $colInfo = 'MEDIUMBLOB'; break; } # switch return $colInfo; } # nativeDtToSw /* controleert of een index bestaat */ function indexExists($idxname, $tablename) { $q = $this->_dbcon->arrayQuery("SHOW INDEXES FROM " . $tablename . " WHERE key_name = '%s'", Array($idxname)); return !empty($q); } # indexExists /* controleert of een column bestaat */ function columnExists($tablename, $colname) { $q = $this->_dbcon->arrayQuery("SHOW COLUMNS FROM " . $tablename . " WHERE Field = '%s'", Array($colname)); return !empty($q); } # columnExists /* Add an index, kijkt eerst wel of deze index al bestaat */ function addIndex($idxname, $idxType, $tablename, $colList) { if (!$this->indexExists($idxname, $tablename)) { if ($idxType == "UNIQUE") { $this->_dbcon->rawExec("ALTER IGNORE TABLE " . $tablename . " ADD " . $idxType . " INDEX " . $idxname . "(" . implode(",", $colList) . ");"); } else { $this->_dbcon->rawExec("ALTER TABLE " . $tablename . " ADD " . $idxType . " INDEX " . $idxname . "(" . implode(",", $colList) . ");"); } # else } # if } # addIndex /* controleert of een full text index bestaat */ function ftsExists($ftsname, $tablename, $colList) { foreach($colList as $num => $col) { $indexInfo = $this->getIndexInfo($ftsname . '_' . $num, $tablename); if ((empty($indexInfo)) || (strtolower($indexInfo[0]['column_name']) != strtolower($col))) { return false; } # if } # foreach return true; } # ftsExists /* maakt een full text index aan */ function createFts($ftsname, $tablename, $colList) { foreach($colList as $num => $col) { $indexInfo = $this->getIndexInfo($ftsname . '_' . $num, $tablename); if ((empty($indexInfo)) || (strtolower($indexInfo[0]['column_name']) != strtolower($col))) { $this->dropIndex($ftsname . '_' . $num, $tablename); $this->addIndex($ftsname . '_' . $num, 'FULLTEXT', $tablename, array($col)); } # if } # foreach } # createFts /* dropt en fulltext index */ function dropFts($ftsname, $tablename, $colList) { foreach($colList as $num => $col) { $this->dropIndex($ftsname . '_' . $num, $tablename); } # foreach } # dropFts /* geeft FTS info terug */ function getFtsInfo($ftsname, $tablename, $colList) { $ftsList = array(); foreach($colList as $num => $col) { $tmpIndex = $this->getIndexInfo($ftsname . '_' . $num, $tablename); if (!empty($tmpIndex)) { $ftsList[] = $tmpIndex[0]; } # if } # foreach return $ftsList; } # getFtsInfo /* dropt een index als deze bestaat */ function dropIndex($idxname, $tablename) { # Check eerst of de tabel bestaat, anders kan # indexExists mislukken en een fatal error geven if (!$this->tableExists($tablename)) { return ; } # if if ($this->indexExists($idxname, $tablename)) { $this->_dbcon->rawExec("DROP INDEX " . $idxname . " ON " . $tablename); } # if } # dropIndex /* voegt een column toe, kijkt wel eerst of deze nog niet bestaat */ function addColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation) { if (!$this->columnExists($tablename, $colName)) { # zet de DEFAULT waarde if (strlen($colDefault) != 0) { $colDefault = 'DEFAULT ' . $colDefault; } # if # converteer het kolom type naar het type dat wij gebruiken $colType = $this->swDtToNative($colType); # Zet de collation om naar iets dat we begrijpen switch(strtolower($collation)) { case 'utf8' : $colSetting = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci'; break; case 'ascii' : $colSetting = 'CHARACTER SET ascii'; break; case '' : $colSetting = ''; break; default : throw new Exception("Invalid collation setting"); } # switch # en zet de 'NOT NULL' om naar een string switch($notNull) { case true : $nullStr = 'NOT NULL'; break; default : $nullStr = ''; } # switch $this->_dbcon->rawExec("ALTER TABLE " . $tablename . " ADD COLUMN(" . $colName . " " . $colType . " " . $colSetting . " " . $colDefault . " " . $nullStr . ")"); } # if } # addColumn /* wijzigt een column - controleert *niet* of deze voldoet aan het prototype */ function modifyColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation, $what) { # zet de DEFAULT waarde if (strlen($colDefault) != 0) { $colDefault = 'DEFAULT ' . $colDefault; } # if # converteer het kolom type naar het type dat wij gebruiken $colType = $this->swDtToNative($colType); # Zet de collation om naar iets dat we begrijpen switch(strtolower($collation)) { case 'utf8' : $colSetting = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci'; break; case 'ascii' : $colSetting = 'CHARACTER SET ascii'; break; case '' : $colSetting = ''; break; default : throw new Exception("Invalid collation setting"); } # switch # en zet de 'NOT NULL' om naar een string switch($notNull) { case true : $nullStr = 'NOT NULL'; break; default : $nullStr = ''; } # switch $this->_dbcon->rawExec("ALTER TABLE " . $tablename . " MODIFY COLUMN " . $colName . " " . $colType . " " . $colSetting . " " . $colDefault . " " . $nullStr); } # modifyColumn /* dropt een kolom (mits db dit ondersteunt) */ function dropColumn($colName, $tablename) { if ($this->columnExists($tablename, $colName)) { $this->_dbcon->rawExec("ALTER TABLE " . $tablename . " DROP COLUMN " . $colName); } # if } # dropColumn /* controleert of een tabel bestaat */ function tableExists($tablename) { $q = $this->_dbcon->arrayQuery("SHOW TABLES LIKE '" . $tablename . "'"); return !empty($q); } # tableExists /* ceeert een lege tabel met enkel een ID veld, collation kan UTF8 of ASCII zijn */ function createTable($tablename, $collation) { if (!$this->tableExists($tablename)) { switch(strtolower($collation)) { case 'utf8' : $colSetting = 'CHARSET=utf8 COLLATE=utf8_unicode_ci'; break; case 'ascii' : $colSetting = 'CHARSET=ascii'; break; default : throw new Exception("Invalid collation setting"); } # switch $this->_dbcon->rawExec("CREATE TABLE " . $tablename . " (id INTEGER PRIMARY KEY AUTO_INCREMENT) " . $colSetting); } # if } # createTable /* drop een table */ function dropTable($tablename) { if ($this->tableExists($tablename)) { $this->_dbcon->rawExec("DROP TABLE " . $tablename); } # if } # dropTable /* verandert een storage engine (concept dat enkel mysql kent :P ) */ function alterStorageEngine($tablename, $engine) { $q = $this->_dbcon->singleQuery("SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '" . $tablename . "'"); if (strtolower($q) != strtolower($engine)) { $this->_dbcon->rawExec("ALTER TABLE " . $tablename . " ENGINE=" . $engine); } # if } # alterStorageEngine /* rename een table */ function renameTable($tablename, $newTableName) { $this->_dbcon->rawExec("RENAME TABLE " . $tablename . " TO " . $newTableName); } # renameTable /* dropped een foreign key constraint */ function dropForeignKey($tablename, $colname, $reftable, $refcolumn, $action) { $q = $this->_dbcon->arrayQuery("SELECT CONSTRAINT_NAME FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '" . $tablename . "' AND COLUMN_NAME = '" . $colname . "' AND REFERENCED_TABLE_NAME = '" . $reftable . "' AND REFERENCED_COLUMN_NAME = '" . $refcolumn . "'"); if (!empty($q)) { foreach($q as $res) { $this->_dbcon->rawExec("ALTER TABLE " . $tablename . " DROP FOREIGN KEY " . $res['CONSTRAINT_NAME']); } # foreach } # if } # dropForeignKey /* creeert een foreign key constraint */ function addForeignKey($tablename, $colname, $reftable, $refcolumn, $action) { $q = $this->_dbcon->arrayQuery("SELECT * FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '" . $tablename . "' AND COLUMN_NAME = '" . $colname . "' AND REFERENCED_TABLE_NAME = '" . $reftable . "' AND REFERENCED_COLUMN_NAME = '" . $refcolumn . "'"); if (empty($q)) { $this->_dbcon->rawExec("ALTER TABLE " . $tablename . " ADD FOREIGN KEY (" . $colname . ") REFERENCES " . $reftable . " (" . $refcolumn . ") " . $action); } # if } # addForeignKey /* Geeft, in een afgesproken formaat, de index formatie terug */ function getColumnInfo($tablename, $colname) { $q = $this->_dbcon->arrayQuery("SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, COLUMN_TYPE, CHARACTER_SET_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = '" . $tablename . "' AND COLUMN_NAME = '" . $colname . "' AND TABLE_SCHEMA = DATABASE()"); if (!empty($q)) { $q = $q[0]; $q['NOTNULL'] = ($q['IS_NULLABLE'] != 'YES'); # MySQL's boolean type is stiekem een tinyint, maar wij verwachten # binnen spotweb een echte boolean. Dus we converteren dat stiekem if (strtolower($q['COLUMN_TYPE']) == 'tinyint(1)') { if (is_numeric($q['COLUMN_DEFAULT'])) { if ($q['COLUMN_DEFAULT']) { $q['COLUMN_DEFAULT'] = '1'; } else { $q['COLUMN_DEFAULT'] = '0'; } # if } # if } # if # converteer het default waarde naar iets anders if ((strlen($q['COLUMN_DEFAULT']) == 0) && (is_string($q['COLUMN_DEFAULT']))) { $q['COLUMN_DEFAULT'] = "''"; } # if } # if return $q; } # getColumnInfo /* Geeft, in een afgesproken formaat, de index informatie terug */ function getIndexInfo($idxname, $tablename) { $q = $this->_dbcon->arrayQuery("SELECT column_name, non_unique, lower(index_type) as index_type FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND table_name = '" . $tablename . "' AND index_name = '" . $idxname . "' ORDER BY seq_in_index"); return $q; } # getIndexInfo } # classdebian/db-update/v20111210/lib/dbstruct/SpotStruct_abs.php0000644000000000000000000011344112267045571020215 0ustar _spotdb = $spotdb; $this->_dbcon = $spotdb->getDbHandle(); } # __construct /* * optimaliseer/analyseer een aantal tables welke veel veranderen, * deze functie wijzigt geen data! */ abstract function analyze(); /* converteert een "spotweb" datatype naar een mysql datatype */ abstract function swDtToNative($colType); /* converteert een mysql datatype naar een "spotweb" datatype */ abstract function nativeDtToSw($colInfo); /* * Add an index, kijkt eerst wel of deze index al bestaat, * $idxType kan danwel 'UNIQUE' danwel 'FULLTEXT' zijn */ abstract function addIndex($idxname, $idxType, $tablename, $colList); /* dropt een index als deze bestaat */ abstract function dropIndex($idxname, $tablename); /* voegt een column toe, kijkt wel eerst of deze nog niet bestaat */ abstract function addColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation); /* wijzigt een column - controleert *niet* of deze voldoet aan het prototype */ abstract function modifyColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation, $what); /* dropt een kolom (mits db dit ondersteunt) */ abstract function dropColumn($colName, $tablename); /* controleert of een index bestaat */ abstract function indexExists($idxname, $tablename); /* controleert of een kolom bestaat */ abstract function columnExists($tablename, $colname); /* controleert of een tabel bestaat */ abstract function tableExists($tablename); /* controleert of een full text index bestaat */ abstract function ftsExists($ftsname, $tablename, $colList); /* maakt een full text index aan */ abstract function createFts($ftsname, $tablename, $colList); /* dropt en fulltext index */ abstract function dropFts($ftsname, $tablename, $colList); /* geeft FTS info terug */ abstract function getFtsInfo($ftsname, $tablename, $colList); /* ceeert een lege tabel met enkel een ID veld, collation kan UTF8 of ASCII zijn */ abstract function createTable($tablename, $collation); /* creeert een foreign key constraint */ abstract function addForeignKey($tablename, $colname, $reftable, $refcolumn, $action); /* dropped een foreign key constraint */ abstract function dropForeignKey($tablename, $colname, $reftable, $refcolumn, $action); /* verandert een storage engine (concept dat enkel mysql kent :P ) */ abstract function alterStorageEngine($tablename, $engine); /* drop een table */ abstract function dropTable($tablename); /* rename een table */ abstract function renameTable($tablename, $newTableName); /* Geeft, in een afgesproken formaat, de index informatie terug */ abstract function getIndexInfo($idxname, $tablename); /* Geeft, in een afgesproken formaat, de index formatie terug */ abstract function getColumnInfo($tablename, $colname); /* controleert of de index structuur hetzelfde is als de gewenste, zo niet, maak hem opnieuw aan */ function validateIndex($idxname, $type, $tablename, $colList) { echo "\tValidating index " . $idxname . PHP_EOL; if (!$this->compareIndex($idxname, $type, $tablename, $colList)) { # Drop de index if ($this->indexExists($idxname, $tablename)) { echo "\t\tDropping index " . $idxname . PHP_EOL; $this->dropIndex($idxname, $tablename); } # if echo "\t\tAdding index " . $idxname . PHP_EOL; # en creeer hem opnieuw $this->addIndex($idxname, $type, $tablename, $colList); } # if } # validateIndex /* controleert of de fulltext structuur hetzelfde is als de gewenste, zo niet, maak hem opnieuw aan */ function validateFts($ftsname, $tablename, $colList) { echo "\tValidating FTS " . $ftsname . PHP_EOL; if (!$this->compareFts($ftsname, $tablename, $colList)) { # Drop de FTS if ($this->ftsExists($ftsname, $tablename, $colList)) { echo "\t\tDropping FTS " . $ftsname . PHP_EOL; $this->dropFts($ftsname, $tablename, $colList); } # if echo "\t\tAdding FTS " . $ftsname . PHP_EOL; # en creeer hem opnieuw $this->createFts($ftsname, $tablename, $colList); } # if } # validateFts /* controleert of de index structuur hetzelfde is als de gewenste, zo niet, maak hem opnieuw aan */ function validateColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation) { echo "\tValidating " . $tablename . "(" . $colName . ")" . PHP_EOL; $compResult = $this->compareColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation); if ($compResult !== true) { if ($this->columnExists($tablename, $colName)) { echo "\t\tModifying column " . $colName . " (" . $compResult . ") on " . $tablename . PHP_EOL; $this->modifyColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation, $compResult); } else { echo "\t\tAdding column " . $colName . "(" . $colType . ") to " . $tablename . PHP_EOL; $this->addColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation); } # else } # if } # validateColumn /* vergelijkt een column met de gewenste structuur */ function compareColumn($colName, $tablename, $colType, $colDefault, $notNull, $collation) { # Vraag nu de column informatie op $q = $this->getColumnInfo($tablename, $colName); # Als de column helemaal niet gevonden wordt.. if (empty($q)) { return false; } # if # controleer het type if (strtolower($q['COLUMN_TYPE']) != strtolower($this->swDtToNative($colType))) { #var_dump($q); #var_dump($colType); #var_dump($this->swDtToNative($colType)); #die(); return 'type'; } # if # controleer default if (strtolower($q['COLUMN_DEFAULT']) != strtolower($colDefault)) { return 'default'; } # if # controleer NOT NULL setting if (strtolower($q['NOTNULL']) != $notNull) { return 'not null'; } # if # controleer NOT NULL setting if ((strtolower($q['CHARACTER_SET_NAME']) != $collation) && ($q['CHARACTER_SET_NAME'] != null)) { return 'charset'; } # if return true; } # compareColumn /* vergelijkt een index met de gewenste structuur */ function compareIndex($idxname, $type, $tablename, $colList) { # Vraag nu de index informatie op $q = $this->getIndexInfo($idxname, $tablename); # Als het aantal kolommen niet gelijk is if (count($q) != count($colList)) { return false; } # if # we loopen vervolgens door elke index kolom heen, en vergelijken # dan of ze in dezelfde volgorde staan en dezelfde eigenschappen hebben for($i = 0; $i < count($colList); $i++) { $same = true; if ($colList[$i] != $q[$i]['column_name']) { $same = false; } # if if ($same) { switch(strtolower($type)) { case 'fulltext' : $same = (strtolower($q[$i]['index_type']) == 'fulltext'); break; case 'unique' : $same = ($q[$i]['non_unique'] == 0); break; case '' : $same = (strtolower($q[$i]['index_type']) != 'fulltext') && ($q[$i]['non_unique'] == 1); } # switch } # if if (!$same) { #var_dump($q[$i]); #var_dump($type); #var_dump($colList); #die(); return false; } # if } # for return true; } # compareIndex /* vergelijkt een FTS met de gewenste structuur */ function compareFts($ftsname, $tablename, $colList) { # Vraag nu de FTS informatie op $q = $this->getFtsInfo($ftsname, $tablename, $colList); # Als het aantal kolommen niet gelijk is if (count($q) != count($colList)) { return false; } # if # we loopen vervolgens door elke index kolom heen, en vergelijken # dan of ze in dezelfde volgorde staan en dezelfde eigenschappen hebben for($i = 0; $i < count($colList); $i++) { if ($colList[$i + 1] != $q[$i]['column_name']) { return false; } # if } # for return true; } # compareFts function updateSchema() { # drop eventueel FTS indexes op de spotsfull tabel $this->dropIndex("idx_spotsfull_fts_1", "spotsfull"); $this->dropIndex("idx_spotsfull_fts_2", "spotsfull"); $this->dropIndex("idx_spotsfull_fts_3", "spotsfull"); $this->dropIndex("idx_spotsfull_2", "spotsfull"); # Index on userid $this->dropIndex("idx_nntp_2", "nntp"); $this->dropIndex("idx_nntp_3", "nntp"); # relaties wissen $this->dropForeignKey('spotsfull', 'messageid', 'spots', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->dropForeignKey('spotstatelist', 'messageid', 'spots', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->dropForeignKey('commentsposted', 'inreplyto', 'spots', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->dropForeignKey('commentsposted', 'messageid', 'spots', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->dropForeignKey('commentsxover', 'messageid', 'spots', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->dropForeignKey('commentsfull', 'messageid', 'spots', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->dropForeignKey('reportsposted', 'inreplyto', 'spots', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->dropForeignKey('reportsposted', 'messageid', 'spots', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); ############################################################################################## # Opschonen data ############################################################################# ############################################################################################## if (($this instanceof SpotStruct_mysql) && (false)) { echo "Cleaning up old data..." . PHP_EOL; if ($this->tableExists('usersettings') && $this->tableExists('users')) { $this->_dbcon->rawExec("DELETE usersettings FROM usersettings LEFT JOIN users ON usersettings.userid=users.id WHERE users.id IS NULL"); } # if if ($this->tableExists('sessions') && $this->tableExists('users')) { $this->_dbcon->rawExec("DELETE sessions FROM sessions LEFT JOIN users ON sessions.userid=users.id WHERE users.id IS NULL"); } # if if ($this->tableExists('spotstatelist') && $this->tableExists('users')) { $this->_dbcon->rawExec("DELETE spotstatelist FROM spotstatelist LEFT JOIN users ON spotstatelist.ouruserid=users.id WHERE users.id IS NULL"); } # if if ($this->tableExists('usergroups') && $this->tableExists('users')) { $this->_dbcon->rawExec("DELETE usergroups FROM usergroups LEFT JOIN users ON usergroups.userid=users.id WHERE users.id IS NULL"); } # if if ($this->tableExists('usergroups') && $this->tableExists('securitygroups')) { $this->_dbcon->rawExec("DELETE usergroups FROM usergroups LEFT JOIN securitygroups ON usergroups.groupid=securitygroups.id WHERE securitygroups.id IS NULL"); } # if if ($this->tableExists('grouppermissions') && $this->tableExists('securitygroups')) { $this->_dbcon->rawExec("DELETE grouppermissions FROM grouppermissions LEFT JOIN securitygroups ON grouppermissions.groupid=securitygroups.id WHERE securitygroups.id IS NULL"); } # if if ($this->tableExists('commentsposted') && $this->tableExists('users')) { $this->_dbcon->rawExec("DELETE commentsposted FROM commentsposted LEFT JOIN users ON commentsposted.ouruserid=users.id WHERE users.id IS NULL"); } # if if ($this->tableExists('commentsposted') && $this->tableExists('spots')) { $this->_dbcon->rawExec("DELETE commentsposted FROM commentsposted LEFT JOIN spots ON commentsposted.inreplyto=spots.messageid WHERE spots.messageid IS NULL"); } # if if ($this->tableExists('commentsfull') && $this->tableExists('commentsxover')) { $this->_dbcon->rawExec("DELETE commentsfull FROM commentsfull LEFT JOIN commentsxover ON commentsfull.messageid=commentsxover.messageid WHERE commentsxover.messageid IS NULL"); } # if if ($this->tableExists('spotsfull') && $this->tableExists('spots')) { $this->_dbcon->rawExec("DELETE spotsfull FROM spotsfull LEFT JOIN spots ON spotsfull.messageid=spots.messageid WHERE spots.messageid IS NULL"); } # if if ($this->tableExists('spotstatelist') && $this->tableExists('spots')) { $this->_dbcon->rawExec("DELETE spotstatelist FROM spotstatelist LEFT JOIN spots ON spotstatelist.messageid=spots.messageid WHERE spots.messageid IS NULL"); } # if if ($this->tableExists('reportsposted') && $this->tableExists('users')) { $this->_dbcon->rawExec("DELETE reportsposted FROM reportsposted LEFT JOIN users ON reportsposted.ouruserid=users.id WHERE users.id IS NULL"); } # if if ($this->tableExists('reportsposted') && $this->tableExists('spots')) { $this->_dbcon->rawExec("DELETE reportsposted FROM reportsposted LEFT JOIN spots ON reportsposted.inreplyto=spots.messageid WHERE spots.messageid IS NULL"); } # if } # if # ---- spots table ---- # $this->createTable('spots', "utf8"); $this->validateColumn('messageid', 'spots', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('poster', 'spots', 'VARCHAR(128)', NULL, false, 'utf8'); $this->validateColumn('title', 'spots', 'VARCHAR(128)', NULL, false, 'utf8'); $this->validateColumn('tag', 'spots', 'VARCHAR(128)', NULL, false, 'utf8'); $this->validateColumn('category', 'spots', 'INTEGER', NULL, false, ''); $this->validateColumn('subcata', 'spots', 'VARCHAR(64)', NULL, false, 'ascii'); $this->validateColumn('subcatb', 'spots', 'VARCHAR(64)', NULL, false, 'ascii'); $this->validateColumn('subcatc', 'spots', 'VARCHAR(64)', NULL, false, 'ascii'); $this->validateColumn('subcatd', 'spots', 'VARCHAR(64)', NULL, false, 'ascii'); $this->validateColumn('subcatz', 'spots', 'VARCHAR(64)', NULL, false, 'ascii'); $this->validateColumn('stamp', 'spots', 'UNSIGNED INTEGER', NULL, false, ''); $this->validateColumn('reversestamp', 'spots', 'INTEGER', "0", false, ''); $this->validateColumn('filesize', 'spots', 'UNSIGNED BIGINTEGER', "0", true, ''); $this->validateColumn('moderated', 'spots', 'BOOLEAN', NULL, false, ''); $this->validateColumn('commentcount', 'spots', 'INTEGER', "0", false, ''); $this->validateColumn('spotrating', 'spots', 'INTEGER', "0", false, ''); $this->validateColumn('reportcount', 'spots', 'INTEGER', "0", false, ''); $this->validateColumn('spotterid', 'spots', 'VARCHAR(32)', NULL, false, 'ascii'); $this->alterStorageEngine("spots", "MyISAM"); # ---- spotsfull table ---- # $this->createTable('spotsfull', "utf8"); $this->validateColumn('messageid', 'spotsfull', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('verified', 'spotsfull', 'BOOLEAN', NULL, false, ''); $this->validateColumn('usersignature', 'spotsfull', 'VARCHAR(255)', NULL, false, 'ascii'); $this->validateColumn('userkey', 'spotsfull', 'VARCHAR(512)', NULL, false, 'ascii'); $this->validateColumn('xmlsignature', 'spotsfull', 'VARCHAR(255)', NULL, false, 'ascii'); $this->validateColumn('fullxml', 'spotsfull', 'TEXT', NULL, false, 'utf8'); $this->alterStorageEngine("spotsfull", "InnoDB"); # ---- nntp table ---- # $this->createTable('nntp', "utf8"); $this->validateColumn('server', 'nntp', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('maxarticleid', 'nntp', 'INTEGER', NULL, false, ''); $this->validateColumn('nowrunning', 'nntp', 'INTEGER', "0", false, ''); $this->validateColumn('lastrun', 'nntp', 'INTEGER', "0", false, ''); $this->validateColumn('serverdatelastrun', 'nntp', 'VARCHAR(14)', "00000000000000", false, 'ascii'); $this->alterStorageEngine("nntp", "InnoDB"); # ---- commentsxover table ---- # $this->createTable('commentsxover', "ascii"); $this->validateColumn('messageid', 'commentsxover', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('nntpref', 'commentsxover', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('spotrating', 'commentsxover', 'INTEGER', "0", false, ''); $this->validateColumn('moderated', 'commentsxover', 'BOOLEAN', NULL, false, ''); $this->alterStorageEngine("commentsxover", "InnoDB"); # ---- reportsxover table ---- # $this->createTable('reportsxover', "ascii"); $this->validateColumn('messageid', 'reportsxover', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('fromhdr', 'reportsxover', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('keyword', 'reportsxover', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('nntpref', 'reportsxover', 'VARCHAR(128)', "''", true, 'ascii'); $this->alterStorageEngine("reportsxover", "InnoDB"); # ---- spotstatelist table ---- # $this->createTable('spotstatelist', "ascii"); $this->validateColumn('messageid', 'spotstatelist', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('ouruserid', 'spotstatelist', 'INTEGER', "0", false, ''); $this->validateColumn('download', 'spotstatelist', 'INTEGER', NULL, false, ''); $this->validateColumn('watch', 'spotstatelist', 'INTEGER', NULL, false, ''); $this->validateColumn('seen', 'spotstatelist', 'INTEGER', NULL, false, ''); $this->alterStorageEngine("spotstatelist", "InnoDB"); # ---- commentsfull table ---- # $this->createTable('commentsfull', "ascii"); $this->validateColumn('messageid', 'commentsfull', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('fromhdr', 'commentsfull', 'VARCHAR(128)', NULL, false, 'utf8'); $this->validateColumn('stamp', 'commentsfull', 'INTEGER', NULL, false, ''); $this->validateColumn('usersignature', 'commentsfull', 'VARCHAR(255)', NULL, false, 'ascii'); $this->validateColumn('userkey', 'commentsfull', 'VARCHAR(512)', NULL, false, 'ascii'); $this->validateColumn('spotterid', 'commentsfull', 'VARCHAR(32)', NULL, false, 'ascii'); $this->validateColumn('hashcash', 'commentsfull', 'VARCHAR(255)', NULL, false, 'ascii'); $this->validateColumn('body', 'commentsfull', 'TEXT', NULL, false, 'utf8'); $this->validateColumn('verified', 'commentsfull', 'BOOLEAN', NULL, false, ''); $this->validateColumn('avatar', 'commentsfull', 'TEXT', NULL, false, 'ascii'); $this->alterStorageEngine("commentsfull", "InnoDB"); # ---- settings table ---- # $this->createTable('settings', "ascii"); $this->validateColumn('name', 'settings', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('value', 'settings', 'TEXT', NULL, false, 'utf8'); $this->validateColumn('serialized', 'settings', 'boolean', NULL, false, ''); $this->alterStorageEngine("settings", "InnoDB"); # ---- commentsposted table ---- # $this->createTable('commentsposted', "ascii"); $this->validateColumn('ouruserid', 'commentsposted', 'INTEGER', "0", true, ''); $this->validateColumn('messageid', 'commentsposted', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('inreplyto', 'commentsposted', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('randompart', 'commentsposted', 'VARCHAR(32)', "''", true, 'ascii'); $this->validateColumn('rating', 'commentsposted', 'INTEGER', 0, true, ''); $this->validateColumn('body', 'commentsposted', 'TEXT', NULL, false, 'utf8'); $this->validateColumn('stamp', 'commentsposted', 'INTEGER', "0", true, ''); $this->alterStorageEngine("commentsposted", "InnoDB"); # ---- spotsposted table ---- # $this->createTable('spotsposted', "utf8"); $this->validateColumn('messageid', 'spotsposted', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('ouruserid', 'spotsposted', 'INTEGER', "0", true, ''); $this->validateColumn('stamp', 'spotsposted', 'UNSIGNED INTEGER', NULL, false, ''); $this->validateColumn('title', 'spotsposted', 'VARCHAR(128)', NULL, false, 'utf8'); $this->validateColumn('tag', 'spotsposted', 'VARCHAR(128)', NULL, false, 'utf8'); $this->validateColumn('category', 'spotsposted', 'INTEGER', NULL, false, ''); $this->validateColumn('subcats', 'spotsposted', 'VARCHAR(255)', NULL, false, 'ascii'); $this->validateColumn('filesize', 'spotsposted', 'UNSIGNED BIGINTEGER', "0", true, ''); $this->validateColumn('fullxml', 'spotsposted', 'TEXT', NULL, false, 'utf8'); $this->alterStorageEngine("spotsposted", "InnoDB"); # ---- reportsposted table ---- # $this->createTable('reportsposted', "ascii"); $this->validateColumn('ouruserid', 'reportsposted', 'INTEGER', "0", true, ''); $this->validateColumn('messageid', 'reportsposted', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('inreplyto', 'reportsposted', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('randompart', 'reportsposted', 'VARCHAR(32)', "''", true, 'ascii'); $this->validateColumn('body', 'reportsposted', 'TEXT', NULL, false, 'utf8'); $this->validateColumn('stamp', 'reportsposted', 'INTEGER', "0", true, ''); $this->alterStorageEngine("reportsposted", "InnoDB"); # ---- usersettings table ---- # $this->createTable('usersettings', "utf8"); $this->validateColumn('userid', 'usersettings', 'INTEGER', '0', true, ''); $this->validateColumn('privatekey', 'usersettings', "TEXT", NULL, false, 'ascii'); $this->validateColumn('publickey', 'usersettings', "TEXT", NULL, false, 'ascii'); $this->validateColumn('avatar', 'usersettings', "TEXT", NULL, false, 'ascii'); $this->validateColumn('otherprefs', 'usersettings', "TEXT", NULL, false, 'utf8'); $this->alterStorageEngine("usersettings", "InnoDB"); # ---- users table ---- # $this->createTable('users', "utf8"); $this->validateColumn('username', 'users', "VARCHAR(128)", "''", true, 'utf8'); $this->validateColumn('firstname', 'users', "VARCHAR(128)", "''", true, 'utf8'); $this->validateColumn('passhash', 'users', "VARCHAR(40)", "''", true, 'ascii'); $this->validateColumn('lastname', 'users', "VARCHAR(128)", "''", true, 'utf8'); $this->validateColumn('mail', 'users', "VARCHAR(128)", "''", true, 'utf8'); $this->validateColumn('apikey', 'users', "VARCHAR(32)", "''", true, 'ascii'); $this->validateColumn('lastlogin', 'users', "INTEGER", "0", true, ''); $this->validateColumn('lastvisit', 'users', "INTEGER", "0", true, ''); $this->validateColumn('lastread', 'users', "INTEGER", "0", true, ''); $this->validateColumn('lastapiusage', 'users', "INTEGER", "0", true, ''); $this->validateColumn('deleted', 'users', "BOOLEAN", $this->_dbcon->bool2dt(false), true, ''); $this->alterStorageEngine("users", "InnoDB"); # ---- sessions ---- # $this->createTable('sessions', "ascii"); $this->validateColumn('sessionid', 'sessions', 'VARCHAR(128)', NULL, false, 'ascii'); $this->validateColumn('userid', 'sessions', 'INTEGER', NULL, false, ''); $this->validateColumn('hitcount', 'sessions', 'INTEGER', NULL, false, ''); $this->validateColumn('lasthit', 'sessions', 'INTEGER', NULL, false, ''); $this->validateColumn('ipaddr', 'sessions', "VARCHAR(45)", "''", true, 'ascii'); $this->alterStorageEngine("sessions", "InnoDB"); # ---- securitygroups ---- $this->createTable('securitygroups', "ascii"); $this->validateColumn('name', 'securitygroups', 'VARCHAR(128)', NULL, false, 'ascii'); $this->alterStorageEngine("securitygroups", "InnoDB"); # ---- grouppermissions ---- $this->createTable('grouppermissions', "ascii"); $this->validateColumn('groupid', 'grouppermissions', 'INTEGER', "0", true, ''); $this->validateColumn('permissionid', 'grouppermissions', 'INTEGER', "0", true, ''); $this->validateColumn('objectid', 'grouppermissions', "VARCHAR(128)", "''", true, 'ascii'); $this->validateColumn('deny', 'grouppermissions', "BOOLEAN", $this->_dbcon->bool2dt(false), true, ''); $this->alterStorageEngine("grouppermissions", "InnoDB"); # ---- usergroups ---- $this->createTable('usergroups', "ascii"); $this->validateColumn('userid', 'usergroups', 'INTEGER', "0", true, ''); $this->validateColumn('groupid', 'usergroups', 'INTEGER', "0", true, ''); $this->validateColumn('prio', 'usergroups', 'INTEGER', '1', true, ''); $this->alterStorageEngine("usergroups", "InnoDB"); # ---- notifications ---- $this->createTable('notifications', "ascii"); $this->validateColumn('userid', 'notifications', 'INTEGER', "0", true, ''); $this->validateColumn('stamp', 'notifications', 'INTEGER', "0", true, ''); $this->validateColumn('objectid', 'notifications', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('type', 'notifications', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('title', 'notifications', 'VARCHAR(128)', "''", true, 'utf8'); $this->validateColumn('body', 'notifications', 'TEXT', NULL, false, 'utf8'); $this->validateColumn('sent', 'notifications', 'BOOLEAN', $this->_dbcon->bool2dt(false), true, ''); $this->alterStorageEngine("notifications", "InnoDB"); # ---- filters ---- $this->createTable('filters', "utf8"); $this->validateColumn('userid', 'filters', 'INTEGER', "0", true, ''); $this->validateColumn('filtertype', 'filters', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('title', 'filters', 'VARCHAR(128)', "''", true, 'utf8'); $this->validateColumn('icon', 'filters', 'VARCHAR(128)', "''", true, 'utf8'); $this->validateColumn('torder', 'filters', 'INTEGER', "0", true, ''); $this->validateColumn('tparent', 'filters', 'INTEGER', "0", true, ''); $this->validateColumn('tree', 'filters', 'TEXT', NULL, false, 'ascii'); $this->validateColumn('valuelist', 'filters', 'TEXT', NULL, false, 'utf8'); $this->validateColumn('sorton', 'filters', 'VARCHAR(128)', NULL, false, 'ascii'); $this->validateColumn('sortorder', 'filters', 'VARCHAR(128)', NULL, false, 'ascii'); $this->alterStorageEngine("filters", "InnoDB"); # ---- filtercounts ---- $this->createTable('filtercounts', "utf8"); $this->validateColumn('userid', 'filtercounts', 'INTEGER', "0", true, ''); $this->validateColumn('filterhash', 'filtercounts', 'VARCHAR(40)', "''", true, 'ascii'); $this->validateColumn('currentspotcount', 'filtercounts', 'INTEGER', "0", true, ''); $this->validateColumn('lastvisitspotcount', 'filtercounts', 'INTEGER', "0", true, ''); $this->validateColumn('lastupdate', 'filtercounts', 'INTEGER', "0", true, ''); $this->alterStorageEngine("filtercounts", "InnoDB"); # ---- spotteridblacklist table ---- # $this->createTable('spotteridblacklist', "utf8"); $this->validateColumn('spotterid', 'spotteridblacklist', 'VARCHAR(32)', NULL, false, 'ascii'); $this->validateColumn('ouruserid', 'spotteridblacklist', 'INTEGER', "0", true, ''); $this->validateColumn('origin', 'spotteridblacklist', 'VARCHAR(255)', NULL, false, 'ascii'); $this->alterStorageEngine("spotteridblacklist", "InnoDB"); # oude cache droppen, converteren gaat te vaak fout if (($this->_spotdb->getSchemaVer() < 0.50) && ($this->tableExists('cache'))) { $this->dropTable('cache'); } # if if (($this->_spotdb->getSchemaVer() < 0.51) && ($this->tableExists('cache')) && (!$this->tableExists('cachetmp')) && ($this instanceof SpotStruct_mysql)) { $this->renameTable('cache', 'cachetmp'); } # if # ---- cache table ---- # $this->createTable('cache', "ascii"); $this->validateColumn('resourceid', 'cache', 'VARCHAR(128)', "''", true, 'ascii'); $this->validateColumn('cachetype', 'cache', 'INTEGER', "0", true, ''); $this->validateColumn('stamp', 'cache', 'INTEGER', "0", true, ''); $this->validateColumn('metadata', 'cache', 'TEXT', NULL, false, 'ascii'); $this->validateColumn('serialized', 'cache', 'BOOLEAN', NULL, false, ''); $this->validateColumn('content', 'cache', 'MEDIUMBLOB', NULL, false, ''); $this->alterStorageEngine("cache", "InnoDB"); # ---- permaudit table ---- # $this->createTable('permaudit', "ascii"); $this->validateColumn('stamp', 'permaudit', 'INTEGER', "0", true, ''); $this->validateColumn('userid', 'permaudit', 'INTEGER', "0", true, ''); $this->validateColumn('permissionid', 'permaudit', 'INTEGER', "0", true, ''); $this->validateColumn('objectid', 'permaudit', "VARCHAR(128)", "''", true, 'ascii'); $this->validateColumn('result', 'permaudit', "BOOLEAN", $this->_dbcon->bool2dt(true), true, ''); $this->validateColumn('ipaddr', 'permaudit', "VARCHAR(45)", "''", true, 'ascii'); $this->alterStorageEngine("permaudit", "InnoDB"); ############################################################################################## ### deprecation van oude Spotweb versies ##################################################### ############################################################################################## if ($this->_spotdb->getSchemaVer() > 0.00 && ($this->_spotdb->getSchemaVer() < 0.34)) { if ($this->_spotdb->getSchemaVer() > 0.00 && ($this->_spotdb->getSchemaVer() < 0.30)) { throw new Exception("Je huidige Spotweb database installatie is te oud om in een keer te upgraden naar deze versie." . PHP_EOL . "Download een eerdere versie van spotweb (https://github.com/spotweb/spotweb/zipball/da6ba29071c49ae88823cccfefc39375b37e9bee), " . PHP_EOL . "draai daarmee upgrade-db.php en als die succesvol is, start dan nogmaals de upgrade via deze versie."); } # if # Tabellen terug samenvoegen in een MyISAM tabel if (($this->_spotdb->getSchemaVer() < 0.34) && ($this->tableExists('spottexts'))) { throw new Exception("Je huidige Spotweb database installatie is te oud om in een keer te upgraden naar deze versie." . PHP_EOL . "Download een eerdere versie van spotweb (https://github.com/spotweb/spotweb/zipball/48bc94a63f94959f9fe6b2372b312e35a4d09997), " . PHP_EOL . "draai daarmee upgrade-db.php en als die succesvol is, start dan nogmaals de upgrade via deze versie."); } # if } # if /* * Convert the information from 'spotsfull' to 'spots' table */ if (($this->_spotdb->getSchemaVer() < 0.48) && ($this->_spotdb->getSchemaVer() > 0.00)) { echo PHP_EOL . PHP_EOL; echo 'Converting your spotsfull data to another format' . PHP_EOL; echo 'Please note - if you had spotsfull enabled, this can take a long time' . PHP_EOL; echo PHP_EOL . PHP_EOL; # Empty the blacklist table because the userid column is renamed to spotterid $tmp = $this->_dbcon->rawExec("TRUNCATE spotteridblacklist"); # Update the spotterid field with the userid field $this->_dbcon->rawExec("UPDATE commentsfull SET spotterid = userid"); # MySQL specifieke syntax to update the spots if ($this instanceof SpotStruct_mysql) { $this->_dbcon->rawExec("UPDATE spots s, spotsfull f SET s.spotterid = f.userid WHERE (s.messageid = f.messageid)"); } # if # PostgreSQL (?) specifieke syntax if ($this instanceof SpotStruct_pgsql) { $this->_dbcon->rawExec("UPDATE spots s SET spotterid = spotsfull.userid FROM spotsfull WHERE (s.messageid = spotsfull.messageid)"); } # if } # if # cache omzetten naar nieuw systeem if (($this->_spotdb->getSchemaVer() < 0.51) && ($this->tableExists('cachetmp'))) { $cachetmpCount = $this->_dbcon->singleQuery("SELECT COUNT(1) FROM cachetmp;"); if ($cachetmpCount > 7500) { $dbname = $this->_dbcon->singleQuery("SELECT DATABASE();"); echo PHP_EOL; echo "Converting the cache is not necessary to continue working with SpotWeb. If you don't want" . PHP_EOL; echo "to wait for this conversion, please enter the following command in MySQL or phpMyAdmin:" . PHP_EOL; echo "\tDROP TABLE " . $dbname . ".cachetmp;" . PHP_EOL . PHP_EOL; echo "If you like to convert the cache, enter:" . PHP_EOL; echo "\tINSERT INTO " . $dbname . ".cache SELECT resourceid, cachetype, stamp, metadata, serialized, COMPRESS(content) FROM " . $dbname . ".cachetmp;" . PHP_EOL; echo "\tDROP TABLE " . $dbname . ".cachetmp;" . PHP_EOL . PHP_EOL; echo "After this operation you must run upgrade-db.php again." . PHP_EOL . PHP_EOL; die(); } # if } # if # En creeer de diverse indexen # ---- Indexen op spots ----- $this->validateIndex("idx_spots_1", "UNIQUE", "spots", array("messageid")); $this->validateIndex("idx_spots_2", "", "spots", array("stamp")); $this->validateIndex("idx_spots_3", "", "spots", array("reversestamp")); $this->validateIndex("idx_spots_4", "", "spots", array("category", "subcata", "subcatb", "subcatc", "subcatd", "subcatz")); $this->validateIndex("idx_spots_5", "", "spots", array("spotterid")); $this->validateFts("idx_fts_spots", "spots", array(1 => "poster", 2 => 'title', 3 => 'tag')); # ---- Indexen op nntp ---- $this->validateIndex("idx_nntp_1", "UNIQUE", "nntp", array("server")); # ---- Indexen op spotsfull ---- $this->validateIndex("idx_spotsfull_1", "UNIQUE", "spotsfull", array("messageid")); # ---- Indexen op commentsfull ---- $this->validateIndex("idx_commentsfull_1", "UNIQUE", "commentsfull", array("messageid")); # ---- Indexen op commentsxover ---- $this->validateIndex("idx_commentsxover_1", "UNIQUE", "commentsxover", array("messageid")); $this->validateIndex("idx_commentsxover_2", "", "commentsxover", array("nntpref")); # ---- Indexen op reportsxover ---- $this->validateIndex("idx_reportsxover_1", "UNIQUE", "reportsxover", array("messageid")); $this->validateIndex("idx_reportsxover_2", "", "reportsxover", array("nntpref")); # ---- Indexen op reportsposted ---- $this->validateIndex("idx_reportsposted_1", "UNIQUE", "reportsposted", array("messageid")); $this->validateIndex("idx_reportsposted_2", "UNIQUE", "reportsposted", array("inreplyto", "ouruserid")); $this->validateIndex("idx_reportspostedrel_1", "", "reportsposted", array("ouruserid")); # ---- Indexen op commentsposted ---- $this->validateIndex("idx_commentsposted_1", "UNIQUE", "commentsposted", array("messageid")); $this->validateIndex("idx_commentspostedrel_1", "", "commentsposted", array("ouruserid")); # ---- Indexen op spotsposted ---- $this->validateIndex("idx_spotsposted_1", "UNIQUE", "spotsposted", array("messageid")); $this->validateIndex("idx_spotspostedrel_1", "", "spotsposted", array("ouruserid")); # ---- Indexen op settings ---- $this->validateIndex("idx_settings_1", "UNIQUE", "settings", array("name")); # ---- Indexen op usersettings ---- $this->validateIndex("idx_usersettings_1", "UNIQUE", "usersettings", array("userid")); # ---- Indexen op users ---- $this->validateIndex("idx_users_1", "UNIQUE", "users", array("username")); $this->validateIndex("idx_users_2", "UNIQUE", "users", array("mail")); $this->validateIndex("idx_users_3", "", "users", array("deleted")); $this->validateIndex("idx_users_4", "UNIQUE", "users", array("apikey")); # ---- Indexen op sessions $this->validateIndex("idx_sessions_1", "UNIQUE", "sessions", array("sessionid")); $this->validateIndex("idx_sessions_2", "", "sessions", array("lasthit")); $this->validateIndex("idx_sessions_3", "", "sessions", array("sessionid", "userid")); $this->validateIndex("idx_sessionsrel_1", "", "sessions", array("userid")); # ---- Indexen op spotstatelist ---- $this->validateIndex("idx_spotstatelist_1", "UNIQUE", "spotstatelist", array("messageid", "ouruserid")); $this->validateIndex("idx_spotstatelistrel_1", "", "spotstatelist", array("ouruserid")); # ---- Indexen op securitygroups ---- $this->validateIndex("idx_securitygroups_1", "UNIQUE", "securitygroups", array("name")); # ---- Indexen op grouppermissions ---- $this->validateIndex("idx_grouppermissions_1", "UNIQUE", "grouppermissions", array("groupid", "permissionid", "objectid")); # ---- Indexen op usergroups ---- $this->validateIndex("idx_usergroups_1", "UNIQUE", "usergroups", array("userid", "groupid")); $this->validateIndex("idx_usergroupsrel_1", "", "usergroups", array("groupid")); # ---- Indexen op notifications ---- $this->validateIndex("idx_notifications_1", "", "notifications", array("userid")); $this->validateIndex("idx_notifications_2", "", "notifications", array("sent")); # ---- Indexen op filters ---- $this->validateIndex("idx_filters_1", "", "filters", array("userid", "filtertype", 'tparent', 'torder')); # ---- Indexen op filtercounts ---- $this->validateIndex("idx_filtercounts_1", "UNIQUE", "filtercounts", array("userid", "filterhash")); # ---- Indexen op spotteridblacklist ---- $this->validateIndex("idx_spotteridblacklist_1", "UNIQUE", "spotteridblacklist", array("spotterid", "ouruserid")); # ---- Indexen op cache ---- $this->validateIndex("idx_cache_1", "UNIQUE", "cache", array("resourceid", "cachetype")); $this->validateIndex("idx_cache_2", "", "cache", array("cachetype", "stamp")); # leg foreign keys aan $this->addForeignKey('usersettings', 'userid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('sessions', 'userid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('spotstatelist', 'ouruserid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('usergroups', 'userid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('usergroups', 'groupid', 'securitygroups', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('grouppermissions', 'groupid', 'securitygroups', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('commentsfull', 'messageid', 'commentsxover', 'messageid', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('notifications', 'userid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('commentsposted', 'ouruserid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('reportsposted', 'ouruserid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('filters', 'userid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); $this->addForeignKey('spotsposted', 'ouruserid', 'users', 'id', 'ON DELETE CASCADE ON UPDATE CASCADE'); ############################################################################################## # Hier droppen we kolommen ################################################################### ############################################################################################## $this->dropColumn('filesize', 'spotsfull'); $this->dropColumn('userid', 'spotsfull'); $this->dropColumn('userid', 'spotteridblacklist'); $this->dropColumn('userid', 'commentsfull'); ############################################################################################## # Hier droppen we tabellen ################################################################### ############################################################################################## $this->dropTable('webcache'); $this->dropTable('cachetmp'); # voeg het database schema versie nummer toe $this->_spotdb->updateSetting('schemaversion', SPOTDB_SCHEMA_VERSION); } # updateSchema } # class debian/db-update/v20111210/lib/SpotUpgrader.php0000644000000000000000000000350712267045571016024 0ustar _db = new SpotDb($dbSettings); $this->_db->connect(); $this->_dbEngine = $dbSettings['engine']; } # ctor /* * Upgrade de settings */ function settings($settings) { include "settings.php"; # Creer het settings object $settings = SpotSettings::singleton($this->_db, $settings); $spotSettingsUpgrader = new SpotSettingsUpgrader($this->_db, $settings); $spotSettingsUpgrader->update(); } # settings /* * Upgrade de users */ function users() { include "settings.php"; # Creer het settings object $settings = SpotSettings::singleton($this->_db, $settings); $spotUserUpgrader = new SpotUserUpgrader($this->_db, $settings); $spotUserUpgrader->update(); } # users /* * Creeert en upgrade de database */ function database() { # Instantieeer een struct object switch($this->_dbEngine) { case 'mysql' : case 'pdo_mysql' : $dbStruct = new SpotStruct_mysql($this->_db); break; case 'pdo_pgsql' : $dbStruct = new SpotStruct_pgsql($this->_db); break; case 'pdo_sqlite' : $dbStruct = new SpotStruct_sqlite($this->_db); break; default : throw new Exception("Unknown database engine"); } # switch $dbStruct->updateSchema(); } # database /* * Optimaliseert de database */ function analyze() { # Instantieeer een struct object switch($this->_dbEngine) { case 'mysql' : case 'pdo_mysql' : $dbStruct = new SpotStruct_mysql($this->_db); break; case 'pdo_pgsql' : $dbStruct = new SpotStruct_pgsql($this->_db); break; case 'pdo_sqlite' : $dbStruct = new SpotStruct_sqlite($this->_db); break; default : throw new Exception("Unknown database engine"); } # switch $dbStruct->analyze(); } # analyze } # SpotUpgrader debian/db-update/v20111210/lib/SpotUserSystem.php0000644000000000000000000011253612267045571016401 0ustar _db = $db; $this->_settings = $settings; } # ctor /* * Generates an unique id, mostly used for sessions */ function generateUniqueId() { $sessionId = ''; for($i = 0; $i < 10; $i++) { $sessionId .= base_convert(mt_rand(), 10, 36); } # for return $sessionId; } # generateUniqueId /* * Create a new session for the userid */ private function createNewSession($userid) { # If this is an actual user, we need to have the user record $tmpUser = $this->getUser($userid); /* * If this is an anonymous user, or if the user has never * logged in before, the last visit time is always the * session creation time */ if (($userid == SPOTWEB_ANONYMOUS_USERID) || ($tmpUser['lastlogin'] == 0)) { $tmpUser['lastvisit'] = time(); # Mark everything as read for anonymous users $this->_db->markFilterCountAsSeen($userid); } else { $tmpUser['lastvisit'] = $tmpUser['lastlogin']; } # if # Create a new session record $session = array('sessionid' => $this->generateUniqueId(), 'userid' => $userid, 'hitcount' => 1, 'lasthit' => time(), 'ipaddr' => $this->determineUsersIpAddress() ); $this->_db->addSession($session); return array('user' => $tmpUser, 'session' => $session); } # createNewSession /* * Update the users cookie */ function updateCookie($userSession) { SetCookie("spotsession", $userSession['session']['sessionid'] . '.' . $userSession['user']['userid'], time()+60*60*24*30, '', # path: The default value is the current directory that the cookie is being set in. $this->_settings->get('cookie_host'), false, # Indicates if the cookie should only be transmitted over a secure HTTPS connection from the client. true); # Only available to the HTTP protocol. This means that the cookie won't be accessible by scripting languages, such as JavaScript. } # updateCookie /* * Removes a session from the database. */ function removeSession($sessionId) { $this->_db->deleteSession($sessionId); } # removeSession /* * Removes all users' sessions from the database */ function removeAllUserSessions($userId) { $this->_db->deleteAllUserSessions($userId); } # removeAllUserSessions /* * Checks whether the user already has a session in its cookie. If it * has, we use the existing session, else we create a new one for the * anonymous user. */ function useOrStartSession() { $userSession = false; if (isset($_COOKIE['spotsession'])) { $userSession = $this->validSession($_COOKIE['spotsession']); } # if if ($userSession === false) { /* * If we don't have a session by now, let's create a new * anonymous session. * * UserID is our default anonymous user, but this can be * overriden by the usersystem */ $userSession = $this->createNewSession( $this->_settings->get('nonauthenticated_userid') ); } # if # Initialize the security system $spotSec = new SpotSecurity($this->_db, $this->_settings, $userSession['user'], $userSession['session']['ipaddr']); $userSession['security'] = $spotSec; /* * And always update the cookie even if one already exists, * this prevents the cookie from expiring all of a sudden */ $this->updateCookie($userSession); return $userSession; } # useOrStartSession /* * Password to hash */ function passToHash($password) { return sha1(strrev(substr($this->_settings->get('pass_salt'), 1, 3)) . $password . $this->_settings->get('pass_salt')); } # passToHash /* * Tries to authenticate the user with the given credentials. * Returns an user record when authed, or false if the * authentication fails */ function login($user, $password) { # Sals the password with the unique salt given in the database $password = $this->passToHash($password); # authenticate the user $userId = $this->_db->authUser($user, $password); if ($userId !== false) { /* * If the user is logged in, create a session. * * Order of actions is import here, because * in a new session the lastvisit time is always * set to the lastlogon time, therefore we first * want the session to be created and after that * we can update the last logon time */ $userSession = $this->createNewSession($userId); $this->updateCookie($userSession); # now update the user record with the last logon time $userSession['user']['lastlogin'] = time(); $this->_db->setUser($userSession['user']); # Initialize the security system $userSession['security'] = new SpotSecurity($this->_db, $this->_settings, $userSession['user'], $userSession['session']['ipaddr']); return $userSession; } else { return false; } # else } # login function verifyApi($apikey) { # try to authenticate the user $userId = $this->_db->authUser(false, $apikey); if ($userId !== false && $userId > SPOTWEB_ADMIN_USERID && $apikey != '') { /* * In a normal logon, we need to have a session. * For API logons, we do not want a session because * that would bloat the session table. * * We therefore manually retrieve the user record */ $userRecord['user'] = $this->getUser($userId); # and use the userrecord to update the lastapiusage time $userRecord['user']['lastapiusage'] = time(); $this->_db->setUser($userRecord['user']); # Initialize the security system $userRecord['security'] = new SpotSecurity($this->_db, $this->_settings, $userRecord['user'], $this->determineUsersIpAddress() ); return $userRecord; } else { return false; } # else } # verifyApi /* * Reset the seenstamp timestamp */ function resetReadStamp($user) { $user['lastvisit'] = time(); $user['lastread'] = $this->_db->getMaxMessageTime(); $this->_db->setUser($user); # Mark everything as read for this user $this->_db->markFilterCountAsSeen($user['userid']); return $user; } # resetReadStamp /* * Checks whether an given session is valid. If the session * is valid, this function returns an userrecord */ function validSession($sessionCookie) { $sessionParts = explode(".", $sessionCookie); if (count($sessionParts) != 2) { return false; } # if # Check whether the session is to be found in the database $sessionValid = $this->_db->getSession($sessionParts[0], $sessionParts[1]); if ($sessionValid === false) { return false; } # if # The session is valid, let's update the hit counter and retrieve the user $this->_db->hitSession($sessionParts[0]); $userRecord = $this->getUser($sessionValid['userid']); /* * If the user could not be found, the session wasn't valid after all */ if ($userRecord === false) { return false; } # if /* * Now determine whether we need to update the lastvisit timestamp. * * If the *lasthit* is older than 15 minutes, we update the *lastvisit* * timestamp to the *lasthit* time. * * Basically this makes sure the 'lastvisit' time is only reset when * the user wasn't active on Spotweb for 15 minutes. This ensures us * the unread count for the user doesn't get unset all of a sudden * during a browsing session. */ if ($sessionValid['lasthit'] < (time() - 900)) { $userRecord['lastvisit'] = $sessionValid['lasthit']; /* * Update the last read time to the last spot we find in the * database. Theoreticall this still contains an race condtion * because the spots could be updated by now. * * We ignore this for now to not cause any performance issues */ if ($userRecord['prefs']['auto_markasread']) { # Retrieve the last update stamp from the filters $filterHashes = $this->_db->getCachedFilterCount($userRecord['userid']); /* * Set the lastread stamp to the last time the spotcount was updated * in the filtercounts */ if (!empty($filterHashes)) { $filterKeys = array_keys($filterHashes); $userRecord['lastread'] = $filterHashes[$filterKeys[0]]['lastupdate']; } else { $userRecord['lastread'] = $this->_db->getMaxMessageTime(); } # else # Mark older spots as read for this user $this->_db->resetFilterCountForUser($userRecord['userid']); } # if $this->_db->setUser($userRecord); } # if return array('user' => $userRecord, 'session' => $sessionValid); } # validSession /* * Validates a username */ function validUsername($user) { $invalidNames = array('god', 'mod', 'modje', 'spot', 'spotje', 'spotmod', 'admin', 'drazix', 'moderator', 'superuser', 'supervisor', 'spotnet', 'spotnetmod', 'administrator', 'spotweb', 'root', 'anonymous', 'spotlite'); $validUsername = !in_array(strtolower($user), $invalidNames); if ($validUsername) { $validUsername = strlen($user) >= 3; } # if return $validUsername; } # validUsername /* * Adds a user to the database */ function addUser($user) { if (!$this->validUsername($user['username'])) { throw new Exception("Invalid username"); } # if # Convert the password to an passhash $user['passhash'] = $this->passToHash($user['newpassword1']); # Create an API key $user['apikey'] = md5($this->generateUniqueId()); # and actually add the user to the database $tmpUser = $this->_db->addUser($user); $this->_db->setUserRsaKeys($tmpUser['userid'], $user['publickey'], $user['privatekey']); /* * Now copy the preferences from the anonymous user to this * new user */ $anonUser = $this->_db->getUser(SPOTWEB_ANONYMOUS_USERID); $tmpUser = array_merge($anonUser, $tmpUser); $tmpUser['prefs']['newspotdefault_tag'] = $user['username']; $this->_db->setUser($tmpUser); # and add the user to the default set of groups as configured $this->_db->setUserGroupList($tmpUser['userid'], $this->_settings->get('newuser_grouplist')); # now copy the users' filters to the new user $this->_db->copyFilterList(SPOTWEB_ANONYMOUS_USERID, $tmpUser['userid']); } # addUser() /* * Update a user's group membership */ function setUserGroupList($user, $groupList) { $this->_db->setUserGroupList($user['userid'], $groupList); } # setUserGroupList /* * Update a user's password */ function setUserPassword($user) { # Convert the password to an passhash $user['passhash'] = $this->passToHash($user['newpassword1']); $this->_db->setUserPassword($user); } # setUserPassword /* * Update a user's API key */ function resetUserApi($user) { $user['apikey'] = md5($this->generateUniqueId()); $this->_db->setUser($user); return $user; } # setUserApi /* * Cleanup of user preferences */ function cleanseUserPreferences($prefs, $tpl) { /* * Make sure the user didn't try to submit preferences * we do not support in Spotweb */ foreach(array_diff_key($prefs, $tpl) as $keys => $values) { unset($prefs[$keys]); } # foreach return $prefs; } # cleanseUserPreferences /* * Validate user preferences */ function validateUserPreferences($prefs, $currentPrefs) { $errorList = array(); # Define several arrays with valid settings $validDateFormats = array('human', '%a, %d-%b-%Y (%H:%M)', '%d-%m-%Y (%H:%M)'); $validTemplates = array('we1rdo'); $validDefaultSorts = array('', 'stamp'); $validLanguages = array_keys($this->_settings->get('system_languages')); # Check per page setting $prefs['perpage'] = (int) $prefs['perpage']; if (($prefs['perpage'] < 2) || ($prefs['perpage'] > 250)) { $errorList[] = _('Invalid preference value (perpage)'); } # if # Controleer basis settings if (in_array($prefs['date_formatting'], $validDateFormats) === false) { $errorList[] = _('Invalid user preference value (date_formatting)'); } # if if (in_array($prefs['template'], $validTemplates) === false) { $errorList[] = _('Invalid user preference value (template)'); } # if if (in_array($prefs['user_language'], $validLanguages) === false) { $errorList[] = _('Invalid user preference value (language)'); } # if if (in_array($prefs['defaultsortfield'], $validDefaultSorts) === false) { $errorList[] = _('Invalid user preference value (defaultsortfield)'); } # if # When nzbhandling settings are not entered at all, we default to disable if (!isset($prefs['nzbhandling'])) { $prefs['nzbhandling'] = array('action' => 'disable', 'prepare_action' => 'merge'); } # if # when an sabnzbd host is entered, it has to be a valid URL if ( ($prefs['nzbhandling']['action'] == 'client-sabnzbd') || ($prefs['nzbhandling']['action'] == 'push-sabnzbd') ) { $tmpHost = parse_url($prefs['nzbhandling']['sabnzbd']['url']); if ( ($tmpHost === false) | (!isset($tmpHost['scheme'])) || (($tmpHost['scheme'] != 'http') && ($tmpHost['scheme'] != 'https')) ) { $errorList[] = _('sabnzbd host is not a valid URL'); } # if # SABnzbd URL should always end with a s slash if(substr($prefs['nzbhandling']['sabnzbd']['url'], -1) !== '/') { $prefs['nzbhandling']['sabnzbd']['url'] .= '/'; } # if } # if /* * Convert other settings to booleans so we always have a valid result. * We need to do this because not all browsers post checkboxes in a form in * the same way. */ $prefs['count_newspots'] = (isset($prefs['count_newspots'])) ? true : false; $prefs['keep_seenlist'] = (isset($prefs['keep_seenlist'])) ? true : false; $prefs['auto_markasread'] = (isset($prefs['auto_markasread'])) ? true : false; $prefs['keep_downloadlist'] = (isset($prefs['keep_downloadlist'])) ? true : false; $prefs['keep_watchlist'] = (isset($prefs['keep_watchlist'])) ? true : false; $prefs['show_filesize'] = (isset($prefs['show_filesize'])) ? true : false; $prefs['show_reportcount'] = (isset($prefs['show_reportcount'])) ? true : false; $prefs['show_nzbbutton'] = (isset($prefs['show_nzbbutton'])) ? true : false; $prefs['show_multinzb'] = (isset($prefs['show_multinzb'])) ? true : false; $prefs['show_avatars'] = (isset($prefs['show_avatars'])) ? true : false; $notifProviders = Notifications_Factory::getActiveServices(); foreach ($notifProviders as $notifProvider) { $prefs['notifications'][$notifProvider]['enabled'] = (isset($prefs['notifications'][$notifProvider]['enabled'])) ? true : false; $prefs['notifications'][$notifProvider]['events']['watchlist_handled'] = (isset($prefs['notifications'][$notifProvider]['events']['watchlist_handled'])) ? true : false; $prefs['notifications'][$notifProvider]['events']['nzb_handled'] = (isset($prefs['notifications'][$notifProvider]['events']['nzb_handled'])) ? true : false; $prefs['notifications'][$notifProvider]['events']['retriever_finished'] = (isset($prefs['notifications'][$notifProvider]['events']['retriever_finished'])) ? true : false; $prefs['notifications'][$notifProvider]['events']['report_posted'] = (isset($prefs['notifications'][$notifProvider]['events']['report_posted'])) ? true : false; $prefs['notifications'][$notifProvider]['events']['spot_posted'] = (isset($prefs['notifications'][$notifProvider]['events']['spot_posted'])) ? true : false; $prefs['notifications'][$notifProvider]['events']['user_added'] = (isset($prefs['notifications'][$notifProvider]['events']['user_added'])) ? true : false; } # Twitter tokens are never posted by the form, but they shouldn't be tossed out $prefs['notifications']['twitter']['screen_name'] = $currentPrefs['notifications']['twitter']['screen_name']; $prefs['notifications']['twitter']['access_token'] = $currentPrefs['notifications']['twitter']['access_token']; $prefs['notifications']['twitter']['access_token_secret'] = $currentPrefs['notifications']['twitter']['access_token_secret']; $prefs['notifications']['twitter']['request_token'] = $currentPrefs['notifications']['twitter']['request_token']; $prefs['notifications']['twitter']['request_token_secret'] = $currentPrefs['notifications']['twitter']['request_token_secret']; # We don't want to save megabyts of CSS, so put a limit to the size if (strlen($prefs['customcss'] > 1024 * 10)) { $errorList[] = _('Custom CSS is too large'); } # if # We don't want to save megabytes of default newspot body, so limit it if (strlen($prefs['newspotdefault_tag'] > 90)) { $errorList[] = _('Default value for a spots\' tag is too long'); } # if if (strlen($prefs['newspotdefault_body'] > 9000)) { $errorList[] = _('Default value for a spots\' body is too long'); } # if # When a 'runcommand' or 'save' action is chosen, 'local_dir' is a mandatry setting if (($prefs['nzbhandling']['action'] == 'save') || ($prefs['nzbhandling']['action'] == 'runcommand')) { if (empty($prefs['nzbhandling']['local_dir'])) { $errorList[] = _('When NZB handling is either "save" or "runcommand" the directory must be entered'); } # if } # if # When a 'runcommand' action is chosen, 'command' is a mandatry setting if ($prefs['nzbhandling']['action'] == 'runcommand') { if (empty($prefs['nzbhandling']['command'])) { $errorList[] = _('When NZB handling is "runcommand" a command must be entered'); } # if } # if # For the 'growl' notification provider, a host is mandatory if ($prefs['notifications']['growl']['enabled']) { if (empty($prefs['notifications']['growl']['host'])) { $errorList[] = _('Growl notifications require a growl host to be entered'); } # if } # if # 'Notify My Android' requires an API key if ($prefs['notifications']['nma']['enabled']) { if (empty($prefs['notifications']['nma']['api'])) { $errorList[] = _('"Notify My Android" notifications require an API key'); } # if } # if # 'Notifo' requires both a username and apikey if ($prefs['notifications']['notifo']['enabled']) { if (empty($prefs['notifications']['notifo']['username'])) { $errorList[] = _('"Notifo" notifications require an username to be entered'); } # if if (empty($prefs['notifications']['notifo']['api'])) { $errorList[] = _('"Notifo" notifications require an api key to be entered'); } # if } # if # 'Prowl' requires an API key if ($prefs['notifications']['prowl']['enabled']) { if (empty($prefs['notifications']['prowl']['apikey'])) { $errorList[] = _('"Prowl" notifications require an API key to be entered'); } # if } # if # To use Twitter, an twitter account should be defined if ($prefs['notifications']['twitter']['enabled']) { if (empty($prefs['notifications']['twitter']['access_token']) || empty($prefs['notifications']['twitter']['access_token_secret'])) { $errorList[] = _('To use twitter you need to enter and validate a twitter account'); } # if } # if return array($errorList, $prefs); } # validateUserPreferences /* * Validate the user record. Might be used for both adding and changing */ function validateUserRecord($user, $isEdit) { $errorList = array(); # Make sure the username is valid if (!$isEdit) { if (!$this->validUsername($user['username'])) { $errorList[] = _('Invalid username chosen'); } # if } # if # Check a firstname is entered if (strlen($user['firstname']) < 2) { $errorList[] = _('Not a valid firstname'); } # if # Check a lastname is entered if (strlen($user['lastname']) < 2) { $errorList[] = _('Not a valid lastname'); } # if # Make sure a psasword is entered if (strlen($user['newpassword1'] > 0)) { if (strlen($user['newpassword1']) < 5){ $errorList[] = _('Entered password is too short'); } # if } # if # and make sure the passwords match if ($user['newpassword1'] != $user['newpassword2']) { $errorList[] = _('Passwords do not match'); } # if # disallow a user from editting the ANONYMOUS user if ($user['userid'] == SPOTWEB_ANONYMOUS_USERID) { $errorList[] = _('You cannot edit the anonymous account'); } # if # check the mailaddress if (!filter_var($user['mail'], FILTER_VALIDATE_EMAIL)) { $errorList[] = _('Not a valid email address'); } # if # and make sure the mailaddress is unique among all users $emailExistResult = $this->_db->userEmailExists($user['mail']); if (($emailExistResult !== $user['userid']) && ($emailExistResult !== false)) { $errorList[] = _('Mailaddress is alread in use'); } # if return $errorList; } # validateUserRecord /* * Set the users' public and private keys */ function setUserRsaKeys($user, $privateKey, $publicKey) { $this->_db->setUserRsaKeys($user['userid'], $privateKey, $publicKey); } # setUserRsaKeys /* * Validate a group record */ function validateSecGroup($group) { $errorList = array(); # Remove any lingering spaces $group['name'] = trim($group['name']); # Ensure a gorupname is given and it is not too short if (strlen($group['name']) < 3) { $errorList[] = _('Invalid groupname'); } # if /* * Now list all security groups to make sure the groupname * is unique. * * This is not the most efficient way to do stuff, but we * do not expect dozens of security groups so this is acceptable */ $secGroupList = $this->_db->getGroupList(null); foreach($secGroupList as $secGroup) { if ($secGroup['name'] == $group['name']) { if ($secGroup['id'] != $group['id']) { $errorList[] = _('Name is already in use'); } # if } # if } # foreach return array($errorList, $group); } # validateSecGroup /* * Removes a permission from a securitygroup */ function removePermFromSecGroup($groupId, $perm) { $this->_db->removePermFromSecGroup($groupId, $perm); } # removePermFromSecGroup /* * Sets a speific permission in a group to either allow or deny */ function setDenyForPermFromSecGroup($groupId, $perm) { $this->_db->setDenyForPermFromSecGroup($groupId, $perm); } # setDenyForPermFromSecGroup /* * Adds a permission to an security group */ function addPermToSecGroup($groupId, $perm) { $errorList = array(); # Remove any superfluous spaces $perm['objectid'] = trim($perm['objectid']); /* * Make sure this specific permission is unique in the group * * We do not check the deny here, because we do not want * groups with both a deny and an allow setting as the results * would be undefined */ $groupPerms = $this->_db->getGroupPerms($groupId); foreach($groupPerms as $groupPerm) { if (($groupPerm['permissionid'] == $perm['permissionid']) && ($groupPerm['objectid'] == $perm['objectid'])) { # Duplicate permission $errorList[] = _('Permission already exists in this group'); } # if } # foreach # Add the permission to the group if (empty($errorList)) { $this->_db->addPermToSecGroup($groupId, $perm); } # if return $errorList; } # addPermToSecGroup /* * Update a group record */ function setSecGroup($group) { $this->_db->setSecurityGroup($group); } # setSecGroup /* * Add an security group */ function addSecGroup($group) { $this->_db->addSecurityGroup($group); } # addSecGroup /* * Retrieve a group record */ function getSecGroup($groupId) { $tmpGroup = $this->_db->getSecurityGroup($groupId); if (!empty($tmpGroup)) { return $tmpGroup[0]; } else { return false; } # else } # getSecGroup /* * Removes a group record */ function removeSecGroup($group) { $this->_db->removeSecurityGroup($group); } # removeSecGroup /* * Retrieves an user record */ function getUser($userid) { $tmpUser = $this->_db->getUser($userid); return $tmpUser; } # getUser() /* * Retrieves an unformatted filterlist */ function getPlainFilterList($userId, $filterType) { return $this->_db->getPlainFilterList($userId, $filterType); } # get PlainFilterList /* * Retrieves a list of filters (in an hierarchical list) */ function getFilterList($userId, $filterType) { return $this->_db->getFilterList($userId, $filterType); } # getFilterList /* * Retrieves one specific filter */ function getFilter($userId, $filterId) { return $this->_db->getFilter($userId, $filterId); } # getFilter /* * Changes the filter values. * * For now only the following values might be changed: * * * Title * * Order * * Parent */ function changeFilter($userId, $filterForm) { return $this->_db->updateFilter($userId, $filterForm); } # changeFilter /* * Validates a filter */ function validateFilter($filter) { $errorList = array(); # Remove any spaces $filter['title'] = trim(utf8_decode($filter['title']), " \t\n\r\0\x0B"); $filter['title'] = trim(utf8_decode($filter['title']), " \t\n\r\0\x0B"); # Make sure a filter name is valid if (strlen($filter['title']) < 3) { $errorList[] = _('Invalid filter name'); } # if return array($filter, $errorList); } # validateFilter /* * Adds a filter to a user */ function addFilter($userId, $filter) { $errorList = array(); list($filter, $errorList) = $this->validateFilter($filter); # No errors found? add it to the datbase if (empty($errorList)) { $this->_db->addFilter($userId, $filter); } # if return $errorList; } # addFilter /* * Retrieves the users' index filter */ function getIndexFilter($userId) { /* * The users' index filter is usually retrieved two or * thee times for the index page, make sure we don't approach * the database that many times */ $userIndexFilter = $this->_db->getUserIndexFilter($userId); if ($userIndexFilter === false) { return array('tree' => ''); } else { return $userIndexFilter; } # else } # getIndexFilter /* * Add user's index filter */ function setIndexFilter($userId, $filter) { # There can only be one $this->removeIndexFilter($userId); # and actually add the index filter $filter['filtertype'] = 'index_filter'; $this->_db->addFilter($userId, $filter); } # addIndexFilter /* * Remove an index filter */ function removeIndexFilter($userId) { $tmpFilter = $this->_db->getUserIndexFilter($userId); if (!empty($tmpFilter)) { $this->_db->deleteFilter($userId, $tmpFilter['id'], 'index_filter'); } # if } # removeIndexFilter /* * Removes a userfilter */ function removeFilter($userId, $filterId) { $this->_db->deleteFilter($userId, $filterId, 'filter'); } # removeFilter /* * Removes all existing filters for a user, and reset its * filerlist to the one for the 'ANONYMOUS' account */ function resetFilterList($userId) { # Remove all filters $this->_db->removeAllFilters($userId); # and copy them back from the userlist $this->_db->copyFilterList(SPOTWEB_ANONYMOUS_USERID, $userId); } # resetFilterList /* * Set the filterlist as specified */ function setFilterList($userId, $filterList) { # remove all existing filters $this->_db->removeAllFilters($userId); # and add the filters from the list foreach($filterList as $filter) { $this->_db->addFilter($userId, $filter); } # foreach } # setFilterList /* * Copy the filters from a specific user to be the * default filters */ function setFiltersAsDefault($userId) { # Remove all filters for the Anonymous user $this->_db->removeAllFilters(SPOTWEB_ANONYMOUS_USERID); # and copy them from the specified user to anonymous $this->_db->copyFilterList($userId, SPOTWEB_ANONYMOUS_USERID); } # setFiltersAsDefault /* * Update a user record (does not change the password) */ function setUser($user) { /* * We always assume the password is not set using * this function, hence the password is never updated * by setUser() */ $this->_db->setUser($user); } # setUser() /* * Removes an user record */ function removeUser($userid) { $this->_db->deleteUser($userid); } # removeUser() /* * Retrieves an RSA key from the users' record. */ function getUserPrivateRsaKey($userId) { return $this->_db->getUserPrivateRsaKey($userId); } # getUserPrivateRsaKey /* * Converts a list of filters to an XML record which should * be interchangeable */ public function filtersToXml($filterList) { $spotsOverview = new SpotsOverview($this->_db, $this->_settings); # create the XML document $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; $mainElm = $doc->createElement('spotwebfilter'); $mainElm->appendChild($doc->createElement('version', '1.0')); $mainElm->appendChild($doc->createElement('generator', 'SpotWeb v' . SPOTWEB_VERSION)); $doc->appendChild($mainElm); $filterListElm = $doc->createElement('filters'); foreach($filterList as $filter) { $filterElm = $doc->createElement('filter'); $filterElm->appendChild($doc->createElement('id', $filter['id'])); $filterElm->appendChild($doc->createElement('title', $filter['title'])); $filterElm->appendChild($doc->createElement('icon', $filter['icon'])); $filterElm->appendChild($doc->createElement('parent', $filter['tparent'])); $filterElm->appendChild($doc->createElement('order', $filter['torder'])); /* * Now add the tree. We get the list of filters as a tree, but we * want to keep the XML as clean as possible so we try to compress it. * * First we have to extract the tree to a list of selections, strongnots * and excludes */ $dynaList = explode(',', $filter['tree']); list($categoryList, $strongNotList) = $spotsOverview->prepareCategorySelection($dynaList); $treeList = explode(',', $spotsOverview->compressCategorySelection($categoryList, $strongNotList)); $tree = $doc->createElement('tree'); foreach($treeList as $treeItem) { if (!empty($treeItem)) { # determine what type of element this is $treeType = 'include'; if ($treeItem[0] == '~') { $treeType = 'strongnot'; $treeItem = substr($treeItem, 1); } elseif ($treeItem[1] == '!') { $treeType = 'exclude'; $treeItem = substr($treeItem, 1); } # else # and create the XML item $treeElm = $doc->createElement('item', $treeItem); $treeElm->setAttribute('type', $treeType); if (!empty($treeItem)) { $tree->appendChild($treeElm); } # if } # if } # treeItems $filterElm->appendChild($tree); /* * Prepareer the filtervalue list to make it usable for the XML */ $tmpFilterValues = explode('&', $filter['valuelist']); $filterValueList = array(); foreach($tmpFilterValues as $filterValue) { $tmpFilter = explode(':', urldecode($filterValue)); # and create the actual filter if (count($tmpFilter) >= 3) { $filterValueList[] = Array('fieldname' => $tmpFilter[0], 'operator' => $tmpFilter[1], 'value' => join(":", array_slice($tmpFilter, 2))); } # if } # foreach /* * Now add the filter items (text searches etc) */ if (!empty($filterValueList)) { $valuesElm = $doc->createElement('values'); foreach($filterValueList as $filterValue) { # Create the value XML item $itemElm = $doc->createElement('item'); $itemElm->appendChild($doc->createElement('fieldname', $filterValue['fieldname'])); $itemElm->appendChild($doc->createElement('operator', $filterValue['operator'])); $itemElm->appendChild($doc->createElement('value', $filterValue['value'])); $valuesElm->appendChild($itemElm); } # foreach $filterElm->appendChild($valuesElm); } # if /* * Add the sorting items */ if (!empty($filter['sorton'])) { $sortElm = $doc->createElement('sort'); $itemElm = $doc->createElement('item'); $itemElm->appendChild($doc->createElement('fieldname', $filter['sorton'])); $itemElm->appendChild($doc->createElement('direction', $filter['sortorder'])); $sortElm->appendChild($itemElm); $filterElm->appendChild($sortElm); } # if $filterListElm->appendChild($filterElm); } # foreach $mainElm->appendChild($filterListElm); return $doc->saveXML(); } # filtersToXml /* * Translates an XML string back to a list of filters */ public function xmlToFilters($xmlStr) { $filterList = array(); $idMapping = array(); $spotsOverview = new SpotsOverview($this->_db, $this->_settings); /* * Parse the XML file */ $xml = @(new SimpleXMLElement($xmlStr)); # We can only parse version 1.0 of the filters if ( (string) $xml->version != '1.0') { return $filterList; } # if # and try to process all of the filters foreach($xml->xpath('/spotwebfilter/filters/filter') as $filterItem) { $filter['id'] = (string) $filterItem->id; $filter['title'] = (string) $filterItem->title; $filter['icon'] = (string) $filterItem->icon; $filter['tparent'] = (string) $filterItem->parent; $filter['torder'] = (string) $filterItem->order; $filter['filtertype'] = 'filter'; $filter['sorton'] = ''; $filter['sortorder'] = ''; $filter['tree'] = ''; $filter['children'] = array(); /* * start with the tree items */ $treeStr = ""; foreach($filterItem->xpath('tree/item') as $treeItem) { $treeType = (string) $treeItem->attributes()->type; if ($treeType == 'exclude') { $treeStr .= ',!' . $treeItem[0]; } elseif ($treeType == 'strongnot') { $treeStr .= ',~' . $treeItem[0]; } elseif ($treeType == 'include') { $treeStr .= ',' . $treeItem[0]; } # if } # foreach if (strlen($treeStr) > 1) { $treeStr = substr($treeStr, 1); } # if $filter['tree'] = $treeStr; /* * now parse the values (textsearches etc) */ $filterValues = array(); foreach($filterItem->xpath('values/item') as $valueItem) { $value = array(); $filterValues[] = urlencode( (string) $valueItem->fieldname . ':' . (string) $valueItem->operator . ':' . (string) $valueItem->value ); } # foreach $filter['valuelist'] = $filterValues; /* * Sorting elements are optional */ if ($filterItem->sort) { $filter['sorton'] = (string) $filterItem->sort->item->fieldname; $filter['sortorder'] = (string) $filterItem->sort->item->direction; } # if $filterList[$filter['id']] = $filter; } # foreach /* * Now create a tree out of it. We cannot do this the same way * as in SpotDb because we cannot create references to the XPATH * function */ foreach($filterList as $idx => &$filter) { if ($filter['tparent'] != 0) { $filterList[$filter['tparent']]['children'][] =& $filter; unset($filterList[$filter['id']]); } # if } # for return $filterList; } # xmlToFilters /* * Changes the avatar of this user */ function changeAvatar($userId, $imageFile) { $errorList = array(); /* * Don't allow images larger than 4000 bytes */ if (strlen($imageFile) > 4000) { $errorList[] = _('An avatar image has a maximum of 4000 bytes'); } # if /* * Make sure the image can be read, and stuff */ $spotImage = new SpotImage($this->_db); if ($spotImage->getImageInfoFromString($imageFile) === false) { $errorList[] = _('Invalid avatar image was supplied'); } # if if (empty($errorList)) { /* * We store the images base64 encoded */ $imageFile = base64_encode($imageFile); /* * and update the database */ $this->_db->setUserAvatar($userId, $imageFile); } # if return $errorList; } # changeAvatar /* * Blacklist a specific spotter */ function addSpotterToBlacklist($ourUserId, $spotterId, $origin) { $this->_db->addSpotterToBlacklist($spotterId, $ourUserId, $origin); } # addSpotterToBlacklist /* * Removes a specific spotter from the blacklis */ function removeSpotterFromBlacklist($ourUserId, $spotterId) { $this->_db->removeSpotterFromBlacklist($spotterId, $ourUserId); } # removeSpotterFromBlacklist /* * Returns if an spotter is blacklisted */ function isSpotterBlacklisted($ourUserId, $spotterId) { return $this->_db->isSpotterBlacklisted($spotterId, $ourUserId); } # isSpotterBlacklisted /* * Returns the users' remote IP address */ function determineUsersIpAddress() { /* * We now compare the X-Fowarded-For header and it's not clear if this * is the right thing to do. */ foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) { if (array_key_exists($key, $_SERVER) === true) { foreach (explode(',', $_SERVER[$key]) as $ip) { if (filter_var($ip, FILTER_VALIDATE_IP) !== false) { $remote_addr = $ip; } # if } # foreach } # if } # foreach if (isset($remote_addr)) { return $remote_addr; } else { return "N/A"; } # if } # determineUsersIpAddress } # class SpotUserSystem debian/db-update/v20111210/lib/SpotSettings.php0000644000000000000000000002125412267045571016052 0ustar getAllSettings(); # en merge de settings met degene die we door krijgen self::$_settings = array_merge(self::$_dbSettings, self::$_phpSettings); # Override NNTP header/comments settings, als er geen aparte NNTP header/comments server is opgegeven, gebruik die van # de NZB server if ((empty(self::$_settings['nntp_hdr']['host'])) && (!empty(self::$_settings['nntp_nzb']))) { self::$_settings['nntp_hdr'] = self::$_settings['nntp_nzb']; } # if # Hetzelfde voor de NNTP upload server if ((empty(self::$_settings['nntp_post']['host'])) && (!empty(self::$_settings['nntp_nzb']))) { self::$_settings['nntp_post'] = self::$_settings['nntp_nzb']; } # if } # if return self::$_instance; } # singleton /* * Geeft de waarde van de setting terug */ function get($name) { return self::$_settings[$name]; } # get /* * Unset een bepaalde waarde */ function remove($name) { unset(self::$_settings[$name]); $this->_db->removeSetting($name); } # remove /* * Geeft terug of een bepaalde setting uit de database * komt of uit de settings.php file. De settings-file * heeft altijd prioriteit */ function getOrigin($name) { if (isset(self::$_phpSettings[$name])) { return "php"; } else { return "db"; } # if } # getOrigin /* * Set de waarde van de setting, maakt hem ook * meteen persistent dus mee oppassen */ function set($name, $value) { # Als de setting uit PHP komt, dan mag die niet geupdate worden # hier omdat we dan niet meer weten wat er gebeurt. if (isset(self::$_phpSettings[$name])) { throw new InvalidSettingsUpdateException("InvalidSettingUpdat Exception for '" . $name . '"'); } # if # Update onze eigen settings array zodat we meteen up-to-date zijn self::$_settings[$name] = $value; $this->_db->updateSetting($name, $value); } # set /* * Validate settings */ function validateSettings($settings) { $errorList = array(); # Define arrays with valid settings $validNntpEnc = array(false, 'ssl', 'tls'); $validModerationAction = array('disable', 'act', 'markspot'); # Get the given value for NNTP encryption $settings['nntp_nzb']['enc'] = (isset($settings['nntp_nzb']['enc']['switch'])) ? $settings['nntp_nzb']['enc']['select'] : false; $settings['nntp_hdr']['enc'] = (isset($settings['nntp_hdr']['enc']['switch'])) ? $settings['nntp_hdr']['enc']['select'] : false; $settings['nntp_post']['enc'] = (isset($settings['nntp_post']['enc']['switch'])) ? $settings['nntp_post']['enc']['select'] : false; # Trim human-entered text fields $settings['nntp_nzb']['host'] = trim($settings['nntp_nzb']['host']); $settings['nntp_hdr']['host'] = trim($settings['nntp_hdr']['host']); $settings['nntp_post']['host'] = trim($settings['nntp_post']['host']); # Verify settings with the previous declared arrays if (in_array($settings['nntp_nzb']['enc'], $validNntpEnc) === false || in_array($settings['nntp_hdr']['enc'], $validNntpEnc) === false || in_array($settings['nntp_post']['enc'], $validNntpEnc) === false) { $errorList[] = _('Invalid encryption setting'); } # if if (in_array($settings['spot_moderation'], $validModerationAction) === false) { $errorList[] = _('Invalid spot moderation setting'); } # if # Verify settings $settings['cookie_expires'] = (int) $settings['cookie_expires']; if ($settings['cookie_expires'] < 0) { $errorList[] = _('Invalid cookie_expires setting'); } # if $settings['retention'] = (int) $settings['retention']; if ($settings['retention'] < 0) { $errorList[] = _('Invalid retention setting'); } # if if (($settings['retrieve_newer_than'] = strtotime($settings['retrieve_newer_than'])) === false || $settings['retrieve_newer_than'] > time()) { $errorList[] = _('Invalid retrieve_newer_than setting'); } elseif ($settings['retrieve_newer_than'] < 1230789600) { $settings['retrieve_newer_than'] = 1230789600; } # elseif $settings['retrieve_increment'] = (int) $settings['retrieve_increment']; if ($settings['retrieve_increment'] < 1) { $errorList[] = _('Invalid retrieve_increment setting'); } # if # check the mailaddress if (!filter_var($settings['systemfrommail'], FILTER_VALIDATE_EMAIL)) { $errorList[] = _('Not a valid email address'); } # if # converteer overige settings naar boolean zodat we gewoon al weten wat er uitkomt $settings['deny_robots'] = (isset($settings['deny_robots'])) ? true : false; $settings['sendwelcomemail'] = (isset($settings['sendwelcomemail'])) ? true : false; $settings['nntp_nzb']['buggy'] = (isset($settings['nntp_nzb']['buggy'])) ? true : false; $settings['nntp_hdr']['buggy'] = (isset($settings['nntp_hdr']['buggy'])) ? true : false; $settings['nntp_post']['buggy'] = (isset($settings['nntp_post']['buggy'])) ? true : false; $settings['retrieve_full'] = (isset($settings['retrieve_full'])) ? true : false; $settings['prefetch_image'] = (isset($settings['prefetch_image'])) ? true : false; $settings['prefetch_nzb'] = (isset($settings['prefetch_nzb'])) ? true : false; $settings['retrieve_comments'] = (isset($settings['retrieve_comments'])) ? true : false; $settings['retrieve_full_comments'] = (isset($settings['retrieve_full_comments'])) ? true : false; $settings['retrieve_reports'] = (isset($settings['retrieve_reports'])) ? true : false; $settings['enable_timing'] = (isset($settings['enable_timing'])) ? true : false; $settings['enable_stacktrace'] = (isset($settings['enable_stacktrace'])) ? true : false; $settings['prepare_statistics'] = (isset($settings['prepare_statistics'])) ? true : false; $settings['external_blacklist'] = (isset($settings['external_blacklist'])) ? true : false; # Default server settings if they won't be used if (!isset($settings['nntp_hdr']['use'])) { $settings['nntp_hdr'] = array('host' => '', 'user' => '', 'pass' => '', 'enc' => false, 'port' => 119, 'buggy' => false); } # if if (!isset($settings['nntp_post']['use'])) { $settings['nntp_post'] = array('host' => '', 'user' => '', 'pass' => '', 'enc' => false, 'port' => 119, 'buggy' => false); } # if unset($settings['nntp_hdr']['use'], $settings['nntp_post']['use']); return array($errorList, $settings); } # validateSettings function setSettings($settings) { # If we disable the external blacklist, clear all entries if ($settings['external_blacklist'] == false && $this->get('external_blacklist') == true) { $this->_db->removeOldBlackList($this->get('blacklist_url')); } # if # clear some stuff we don't need to store unset($settings['xsrfid'], $settings['http_referer'], $settings['buttonpressed']); # Store settings foreach ($settings as $key => $value) { # and write these updated settings to the database $this->set($key, $value); } # foreach } # setSettings /* * Is onze database versie nog wel geldig? */ function schemaValid() { # SPOTDB_SCHEMA_VERSION is gedefinieerd bovenin SpotDb return ($this->get('schemaversion') == SPOTDB_SCHEMA_VERSION); } # schemaValid /* * Zijn onze settings versie nog wel geldig? */ function settingsValid() { # SPOTWEB_SETTINGS_VERSION is gedefinieerd bovenin dit bestand return ($this->get('settingsversion') == SPOTWEB_SETTINGS_VERSION); } # settingsValid /* * Bestaat de opgegeven setting ? */ function exists($name) { return isset(self::$_settings[$name]); } # isSet /* * Private constructor, moet altijd via singleton gaan */ private function __construct($db) { $this->_db = $db; } # ctor } # class SpotSettings debian/db-update/v20111210/lib/exceptions/0000755000000000000000000000000012267045571015050 5ustar debian/db-update/v20111210/lib/exceptions/InvalidSettingsUpdateException.php0000644000000000000000000000011212267045571023704 0ustar message}' in {$this->file}({$this->line})\n" . "{$this->getTraceAsString()}"; } } ?>debian/db-update/v20111210/lib/exceptions/InvalidOwnSettingsSettingException.php0000644000000000000000000000011612267045571024567 0ustar rawExec($this->prepareSql($s, $p)); } # exec() /* * INSERT or UPDATE statement, doesn't return anything. Exception * thrown if a error occurs */ abstract function modify($s, $p = array()); /* * Constructs a query part to match textfields. Abstracted so we can use * a database specific FTS engine if one is provided by the DBMS */ function createTextQuery($searchFields) { # Initialize some basic variables so our return statements are simple $filterValueSql = array(); foreach($searchFields as $searchItem) { $searchValue = trim($searchItem['value']); $field = $searchItem['fieldname']; $filterValueSql[] = " (" . $searchItem['fieldname'] . " LIKE '%" . $this->safe($searchValue) . "%') "; } # foreach return array('filterValueSql' => $filterValueSql, 'additionalTables' => array(), 'additionalFields' => array(), 'sortFields' => array()); } # createTextQuery } # dbeng_abs debian/db-update/v20111210/lib/dbeng/dbeng_pdo_mysql.php0000644000000000000000000000245212267045571017630 0ustar _db_host = $host; $this->_db_user = $user; $this->_db_pass = $pass; $this->_db_db = $db; } function connect() { if (!$this->_conn instanceof PDO) { if ($this->_db_host[0] === '/') { $this->_db_conn = "unix_socket=" . $this->_db_host; } else { $this->_db_conn = "host=" . $this->_db_host . ";port=3306"; } try { $this->_conn = new PDO('mysql:' . $this->_db_conn . ';dbname=' . $this->_db_db, $this->_db_user, $this->_db_pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); } catch (PDOException $e) { throw new DatabaseConnectionException($e->getMessage(), -1); } $this->_conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } # if } # connect() /* * Returns a database specific representation of a boolean value */ function bool2dt($b) { if ($b) { return '1'; } # if return '0'; } # bool2dt function safe($s) { $search=array("\\","\0","\n","\r","\x1a","'",'"'); $replace=array("\\\\","\\0","\\n","\\r","\Z","\'",'\"'); return str_replace($search, $replace, $s); } # safe } # class debian/db-update/v20111210/lib/dbeng/dbeng_pdo.php0000644000000000000000000001106412267045571016402 0ustar _conn->prepare($s); } # if $pattern = '/(\'?\%[dsb]\'?)/'; $matches = array(); preg_match_all($pattern, $s, $matches); $s = preg_replace($pattern, '?', $s); $stmt = $this->_conn->prepare($s); $idx=1; $totalCount = count($p); foreach ($matches[1] as $m) { if ($idx > ($totalCount+1)) { break; } # if if (is_null($p[$idx-1])) { $stmt->bindValue($idx, null, PDO::PARAM_NULL); } else { switch ($m) { case '%d': { # We convet explicitly to strval because PDO changes a zero to an '' $stmt->bindParam($idx, strval($p[$idx-1]), PDO::PARAM_INT); break; } case "'%b'": { $stmt->bindParam($idx, $p[$idx-1], PDO::PARAM_LOB); break; } default: { $stmt->bindParam($idx, $p[$idx-1], PDO::PARAM_STR); } } } $idx++; } if (!$stmt instanceof PDOStatement) { throw new Exception(print_r($stmt, true)); } return $stmt; } public function rawExec($s) { SpotTiming::start(__FUNCTION__); try { $stmt = $this->_conn->query($s); } catch(PDOException $x) { throw new SqlErrorException( $x->errorInfo[0] . ': ' . $x->errorInfo[2], -1); } # catch SpotTiming::stop(__FUNCTION__,array($s)); return $stmt; } /* * Returns a database specific representation of a boolean value */ function bool2dt($b) { if ($b) { return '1'; } # if return '0'; } # bool2dt /** * Execute the query and saves the rowcount in a property for later retrieval * * @param string $s * @param array $p * @return PDOStatement */ public function exec($s, $p = array()) { SpotTiming::start(__FUNCTION__); try { $stmt = $this->prepareSql($s, $p); $stmt->execute(); } catch(PDOException $x) { throw new SqlErrorException( $x->errorInfo[0] . ': ' . $x->errorInfo[2], -1); } # catch $this->_rows_changed = $stmt->rowCount(); SpotTiming::stop(__FUNCTION__, array($s, $p)); return $stmt; } /* * INSERT or UPDATE statement, doesn't return anything. Exception * thrown if a error occurs */ function modify($s, $p = array()) { SpotTiming::start(__FUNCTION__); $res = $this->exec($s, $p); $res->closeCursor(); unset($res); SpotTiming::stop(__FUNCTION__, array($s,$p)); } # modify /* * Begins an transaction */ function beginTransaction() { $this->_conn->beginTransaction(); } # beginTransaction /* * Commits an transaction */ function commit() { $this->_conn->commit(); } # commit /* * Rolls back an transaction */ function rollback() { $this->_conn->rollback(); } # rollback function rows() { return $this->_rows_changed; } # rows() function lastInsertId($tableName) { return $this->_conn->lastInsertId($tableName . "_id_seq"); } # lastInsertId /** * Executes the query with $params as parameters. All parameters are * parsed through sthe safe() function to prevent SQL injection. * * Returns a single associative array when query succeeds, returns * an exception when the query fails. * * @param array $s * @param array $p * @return array */ function singleQuery($s, $p = array()) { SpotTiming::start(__FUNCTION__); $stmt = $this->exec($s, $p); $row = $stmt->fetch(); $stmt->closeCursor(); unset($stmt); SpotTiming::stop(__FUNCTION__, array($s,$p)); return $row[0]; } # singleQuery /** * Executes the query with $params as parameters. All parameters are * parsed through sthe safe() function to prevent SQL injection. * * * Returns an array of associative arrays when query succeeds, returns * an exception when the query fails. * * @param string $s * @param array $p * @return array */ function arrayQuery($s, $p = array()) { SpotTiming::start(__FUNCTION__); $stmt = $this->exec($s, $p); $tmpArray = $stmt->fetchAll(); $stmt->closeCursor(); unset($stmt); SpotTiming::stop(__FUNCTION__, array($s,$p)); return $tmpArray; } # arrayQuery } # class debian/db-update/v20111210/lib/SpotSettingsUpgrader.php0000644000000000000000000001176112267045571017546 0ustar _db = $db; $this->_settings = $settings; } # ctor function update() { # Zorg dat de diverse versienummers altijd in de db staan zodat # we er mee kunnen vergelijken $this->setIfNot("settingsversion", "0.00"); $this->setIfNot("securityversion", "0.00"); if ($this->_settings->get('settingsversion') < 0.15) { $this->remove('system_languages'); } # if $this->createServerKeys($this->_settings->get('openssl_cnf_path')); $this->createPasswordSalt(); $this->setupNewsgroups(); $this->createRsaKeys(); $this->createXsrfSecret(); $this->remove('sabnzbdurltpl'); $this->remove('sabnzbdurl'); $this->remove('recompress_nzb'); $this->remove('available_languages'); $this->remove('featureversion'); $this->remove('max_newcount'); $this->setIfNot('cookie_expires', 30); $this->setIfNot('sendwelcomemail', true); $this->setIfNot('twitter_consumer_key', 'LRJCpeHASigYtWEmxoNPA'); $this->setIfNot('twitter_consumer_secret', 'QvwZglJNpzAnoVDt40uUyu5dRDlVFVs4ddxfEkYp7A'); // This secret can be shared $this->setIfNot('boxcar_api_key', 'pOQM9O2AnEWL0RjSoHln'); $this->setIfNot('boxcar_api_secret', '7CwTFfX7KeAKfjM1DJjg5s9qcHm4cwmLkxQgW9fe'); // This secret can be shared $this->setIfNot('auditlevel', 0); // No auditing $this->setIfNot('system_languages', array('nl_NL' => 'Nederlands', 'en_US' => 'English')); $this->setIfNot('retention', 0); $this->setIfNot('deny_robots', true); $this->setIfNot('nntp_nzb', array('host' => '', 'user' => '', 'pass' => '', 'enc' => false, 'port' => 119, 'buggy' => false)); $this->setIfNot('nntp_hdr', array('host' => '', 'user' => '', 'pass' => '', 'enc' => false, 'port' => 119, 'buggy' => false)); $this->setIfNot('nntp_post', array('host' => '', 'user' => '', 'pass' => '', 'enc' => false, 'port' => 119, 'buggy' => false)); $this->setIfNot('retrieve_newer_than', 0); $this->setIfNot('retrieve_full', true); $this->setIfNot('prefetch_image', false); $this->setIfNot('prefetch_nzb', false); $this->setIfNot('retrieve_comments', true); $this->setIfNot('retrieve_full_comments', false); $this->setIfNot('retrieve_reports', true); $this->setIfNot('retrieve_increment', 1000); $this->setIfNot('spot_moderation', 'act'); $this->setIfNot('prepare_statistics', true); $this->setIfNot('external_blacklist', true); $this->setIfNot('blacklist_url', 'http://jij.haatmij.nl/spotnet/blacklist.txt'); $this->setIfNot('enable_timing', false); $this->setIfNot('enable_stacktrace', true); $this->setIfNot('systemfrommail', 'spotweb@example.com'); $this->updateSettingsVersion(); } # update() /* * Set een setting alleen als hij nog niet bestaat */ function setIfNot($name, $value) { if ($this->_settings->exists($name)) { return ; } # if $this->_settings->set($name,$value); } # setIfNot /* * Verwijder een setting */ function remove($name) { $this->_settings->remove($name); } # remove /* * Update de huidige versie van de settings */ function updateSettingsVersion() { $this->_settings->set('settingsversion', SPOTWEB_SETTINGS_VERSION); } # updateSettingsVersion /* * Creeer de server private en public keys */ function createServerKeys($openSslCnfPath) { $spotSigning = new SpotSigning(); $x = $spotSigning->createPrivateKey($openSslCnfPath); $this->setIfNot('publickey', $x['public']); $this->setIfNot('privatekey', $x['private']); } # createServerKeys /* * Creeer de RSA keys */ function createRsaKeys() { # # RSA keys # Worden gebruikt om te valideren of spots geldig zijn, hoef je normaal niet aan te komen # $rsaKeys = array(); $rsaKeys[2] = array('modulo' => 'ys8WSlqonQMWT8ubG0tAA2Q07P36E+CJmb875wSR1XH7IFhEi0CCwlUzNqBFhC+P', 'exponent' => 'AQAB'); $rsaKeys[3] = array('modulo' => 'uiyChPV23eguLAJNttC/o0nAsxXgdjtvUvidV2JL+hjNzc4Tc/PPo2JdYvsqUsat', 'exponent' => 'AQAB'); $rsaKeys[4] = array('modulo' => '1k6RNDVD6yBYWR6kHmwzmSud7JkNV4SMigBrs+jFgOK5Ldzwl17mKXJhl+su/GR9', 'exponent' => 'AQAB'); $this->setIfNot('rsa_keys', $rsaKeys); } # createRsaKeys /* * Create an xsrf secret */ function createXsrfSecret() { $userSystem = new SpotUserSystem($this->_db, $this->_settings); $secret = substr($userSystem->generateUniqueId(), 0, 8); $this->setIfNot('xsrfsecret', $secret); } # createXsrfSecret /* * Creer de servers' password salt */ function createPasswordSalt() { $userSystem = new SpotUserSystem($this->_db, $this->_settings); $salt = $userSystem->generateUniqueId() . $userSystem->generateUniqueId(); $this->setIfNot('pass_salt', $salt); } # createPasswordSalt /* * Definieer de standaard SpotNet groepen */ function setupNewsgroups() { $this->setIfNot('hdr_group', 'free.pt'); $this->setIfNot('nzb_group', 'alt.binaries.ftd'); $this->setIfNot('comment_group', 'free.usenet'); $this->setIfNot('report_group', 'free.willey'); } # setupNewsgroups() } # SpotSettingsUpgrader debian/db-update/v20111210/lib/SpotSigning.php0000644000000000000000000002055512267045571015653 0ustar _nativeVerify = new SpotSeclibToOpenSsl(); } # if } # ctor private function checkRsaSignature($toCheck, $signature, $rsaKey, $useCache) { # de signature is base64 encoded, eerst decoden $signature = base64_decode($signature); # Controleer of we de native OpenSSL libraries moeten # gebruiken om RSA signatures te controleren if (CRYPT_RSA_MODE != CRYPT_RSA_MODE_OPENSSL) { # Initialize the public key to verify with $pubKey['n'] = new Math_BigInteger(base64_decode($rsaKey['modulo']), 256); $pubKey['e'] = new Math_BigInteger(base64_decode($rsaKey['exponent']), 256); # and verify the signature $rsa = new Crypt_RSA(); $rsa->loadKey($pubKey, CRYPT_RSA_PUBLIC_FORMAT_RAW); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); # Supress notice if the signature was invalid $saveErrorReporting = error_reporting(E_ERROR); $tmpSave = $rsa->verify($toCheck, $signature); error_reporting($saveErrorReporting); } else { $tmpSave = $this->_nativeVerify->verify($rsaKey, $toCheck, $signature, $useCache); } # else return $tmpSave; } # checkRsaSignature /* * Creeert een private en public key paar */ public function createPrivateKey($sslCnfPath) { $rsa = new Crypt_RSA(); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); # We hebben deze code geconfigureerd uit Crypt/RSA.php omdat # we anders de configuratie parameter niet mee kunnen geven aan # openssl_pkey_new() if (CRYPT_RSA_MODE != CRYPT_RSA_MODE_OPENSSL) { # We krijgen de keys base encoded terug $keyPair = $rsa->createKey(); return array('public' => $keyPair['publickey'], 'private' => $keyPair['privatekey']); } else { $opensslPrivKey = openssl_pkey_new(array('private_key_bits' => 1024, 'config' => $sslCnfPath)); openssl_pkey_export($opensslPrivKey, $privateKey, null, array('config' => $sslCnfPath)); $publicKey = openssl_pkey_get_details($opensslPrivKey); $publicKey = $publicKey['key']; openssl_free_key($opensslPrivKey); return array('public' => $publicKey, 'private' => $privateKey); } # else } # createPrivateKey /* * RSA signed een bericht, en geeft alle componenten terug * die nodig zijn om dit te valideren, dus: * * - base64 encoded signature (signature) * - Public key (publickey) * - Het bericht dat gesigned is (message) */ public function signMessage($privatekey, $message) { /** * Test code: * * $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); * extract($rsa->createKey()); * $spotSigning = new SpotSigning(); * $x = $spotSigning->signMessage($privatekey, 'testmessage'); * var_dump($x); * var_dump($spotSigning->checkRsaSignature('testmessage', $x['signature'], $x['publickey'], false)); * */ if (empty($privatekey)) { throw new Exception("Given privatekey is invalid, please correct (eg: run upgrade-db.php when testinstall.php is without errors)"); } # if $rsa = new Crypt_RSA(); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $rsa->loadKey($privatekey); # extract de public key $signature = $rsa->sign($message); $publickey = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW); return array('signature' => base64_encode($signature), 'publickey' => array('modulo' => base64_encode($publickey['n']->toBytes()), 'exponent' => base64_encode($publickey['e']->toBytes())), 'message' => $message); } # signMessage /* * Returns a public key */ function getPublicKey($privateKey) { $rsa = new Crypt_RSA(); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $rsa->loadKey($privateKey); # extract de public key $publicKey = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW); return array('publickey' => array('modulo' => base64_encode($publicKey['n']->toBytes()), 'exponent' => base64_encode($publicKey['e']->toBytes()))); } # getPublicKey /* * Converteer een voor ons bruikbare publickey, naar een publickey * formaat gebruikt door de SpotNet native client */ public function pubkeyToXml($pubkey) { return "" . $pubkey['modulo'] . '' . $pubkey['exponent'] . ''; } # pubkeyToXml /* * Helper functie om een spot header (resultaat uit een xover of getHeader()) te verifieeren */ public function verifySpotHeader($spot, $signature, $rsaKeys) { # This is the string to verify $toCheck = $spot['title'] . substr($spot['header'], 0, strlen($spot['header']) - strlen($spot['headersign']) - 1) . $spot['poster']; # Check the RSA signature on the spot return $this->checkRsaSignature($toCheck, $signature, $rsaKeys[$spot['keyid']], true); } # verifySpotHeader() /* * Helper functie om een fullspot te verifieeren */ public function verifyFullSpot($spot) { if ((empty($spot['user-signature'])) || (empty($spot['user-key']))) { return false; } # if $verified = $this->checkRsaSignature('<' . $spot['messageid'] . '>', $spot['user-signature'], $spot['user-key'], false); if ((!$verified) && (!empty($spot['xml-signature']))) { $verified = $this->checkRsaSignature($spot['xml-signature'], $spot['user-signature'], $spot['user-key'], false); } # if return $verified; } # verifyFullSpot() /* * Helper functie om een comment header te verifieeren */ public function verifyComment($comment) { $verified = false; if ((!empty($comment['user-signature'])) && (!empty($comment['user-key']))) { $verified = $this->checkRsaSignature('<' . $comment['messageid'] . '>', $comment['user-signature'], $comment['user-key'], false); if (!$verified) { $verified = $this->checkRsaSignature('<' . $comment['messageid'] . '>' . implode("\r\n", $comment['body']) . "\r\n" . $comment['fromhdr'], $comment['user-signature'], $comment['user-key'], false); } # if } # if # als een spot qua RSA signature al klopt, kunnen we ook nog controleren op de users' # hash, deze zou eigenlijk ook moeten kloppen. # Deze hash is puur gemaakt om rekenkracht te vereisen aan de kant van de poster om # eventuele floods te voorkomen, de hash is dus ook op zich door iedereen te creeeren. # if ($verified) { # $userSignedHash = sha1('<' . $comment['messageid'] . '>', false); # $verified = (substr($userSignedHash, 0, 4) == '0000'); } # if return $verified; } # verifyComment() /* * Bereken een SHA1 hash van het bericht en doe dit net zo lang tot de eerste bytes * bestaan uit 0000. * * Normaal gebruik je hiervoor de JS variant. */ function makeExpensiveHash($prefix, $suffix) { $runCount = 0; $hash = $prefix . $suffix; while(substr($hash, 0, 4) !== '0000') { if ($runCount > 400000) { throw new Exception("Unable to calculate SHA1 hash: " . $runCount); } # if $runCount++; $uniquePart = $this->makeRandomStr(15); $hash = sha1($prefix . $uniquePart . $suffix, false); } # while return $prefix . $uniquePart . $suffix; } # makeExpensiveHash /* * Creeert een random strng van A-Za-z,0-9 van $len length */ function makeRandomStr($len) { $possibleChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; $unique = ''; for($i = 0; $i < $len; $i++) { $unique .= $possibleChars[mt_rand(0, strlen($possibleChars) - 1)]; } # for return $unique; } # makeRandomStr /* * 'Bereken' de userid aan de hand van z'n publickey */ public function calculateSpotterId($userKey) { $userSignCrc = crc32(base64_decode($userKey)); $userIdTmp = chr($userSignCrc & 0xFF) . chr(($userSignCrc >> 8) & 0xFF ). chr(($userSignCrc >> 16) & 0xFF) . chr(($userSignCrc >> 24) & 0xFF); return str_replace(array('/', '+', '='), '', base64_encode($userIdTmp)); } # calculateSpotterId } # class SpotSigning debian/db-update/v20111210/dbsettings.inc.php0000644000000000000000000000046612267045571015556 0ustar * setKey('abcdefg'); * * echo base64_encode($hash->hash('abcdefg')); * ?> * * * LICENSE: This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * @category Crypt * @package Crypt_Hash * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt * @version $Id: Hash.php,v 1.6 2009/11/23 23:37:07 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ /**#@+ * @access private * @see Crypt_Hash::Crypt_Hash() */ /** * Toggles the internal implementation */ define('CRYPT_HASH_MODE_INTERNAL', 1); /** * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+. */ define('CRYPT_HASH_MODE_MHASH', 2); /** * Toggles the hash() implementation, which works on PHP 5.1.2+. */ define('CRYPT_HASH_MODE_HASH', 3); /**#@-*/ /** * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions. * * @author Jim Wigginton * @version 0.1.0 * @access public * @package Crypt_Hash */ class Crypt_Hash { /** * Byte-length of compression blocks / key (Internal HMAC) * * @see Crypt_Hash::setAlgorithm() * @var Integer * @access private */ var $b; /** * Byte-length of hash output (Internal HMAC) * * @see Crypt_Hash::setHash() * @var Integer * @access private */ var $l = false; /** * Hash Algorithm * * @see Crypt_Hash::setHash() * @var String * @access private */ var $hash; /** * Key * * @see Crypt_Hash::setKey() * @var String * @access private */ var $key = ''; /** * Outer XOR (Internal HMAC) * * @see Crypt_Hash::setKey() * @var String * @access private */ var $opad; /** * Inner XOR (Internal HMAC) * * @see Crypt_Hash::setKey() * @var String * @access private */ var $ipad; /** * Default Constructor. * * @param optional String $hash * @return Crypt_Hash * @access public */ function Crypt_Hash($hash = 'sha1') { if ( !defined('CRYPT_HASH_MODE') ) { switch (true) { case extension_loaded('hash'): define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); break; case extension_loaded('mhash'): define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH); break; default: define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL); } } $this->setHash($hash); } /** * Sets the key for HMACs * * Keys can be of any length. * * @access public * @param String $key */ function setKey($key) { $this->key = $key; } /** * Sets the hash function. * * @access public * @param String $hash */ function setHash($hash) { switch ($hash) { case 'md5-96': case 'sha1-96': $this->l = 12; // 96 / 8 = 12 break; case 'md2': case 'md5': $this->l = 16; break; case 'sha1': $this->l = 20; break; case 'sha256': $this->l = 32; break; case 'sha384': $this->l = 48; break; case 'sha512': $this->l = 64; } switch ($hash) { case 'md2': $mode = CRYPT_HASH_MODE_INTERNAL; break; case 'sha384': case 'sha512': $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; break; default: $mode = CRYPT_HASH_MODE; } switch ( $mode ) { case CRYPT_HASH_MODE_MHASH: switch ($hash) { case 'md5': case 'md5-96': $this->hash = MHASH_MD5; break; case 'sha256': $this->hash = MHASH_SHA256; break; case 'sha1': case 'sha1-96': default: $this->hash = MHASH_SHA1; } return; case CRYPT_HASH_MODE_HASH: switch ($hash) { case 'md5': case 'md5-96': $this->hash = 'md5'; return; case 'sha256': case 'sha384': case 'sha512': $this->hash = $hash; return; case 'sha1': case 'sha1-96': default: $this->hash = 'sha1'; } return; } switch ($hash) { case 'md2': $this->b = 16; $this->hash = array($this, '_md2'); break; case 'md5': case 'md5-96': $this->b = 64; $this->hash = array($this, '_md5'); break; case 'sha256': $this->b = 64; $this->hash = array($this, '_sha256'); break; case 'sha384': case 'sha512': $this->b = 128; $this->hash = array($this, '_sha512'); break; case 'sha1': case 'sha1-96': default: $this->b = 64; $this->hash = array($this, '_sha1'); } $this->ipad = str_repeat(chr(0x36), $this->b); $this->opad = str_repeat(chr(0x5C), $this->b); } /** * Compute the HMAC. * * @access public * @param String $text * @return String */ function hash($text) { $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; if (!empty($this->key)) { switch ( $mode ) { case CRYPT_HASH_MODE_MHASH: $output = mhash($this->hash, $text, $this->key); break; case CRYPT_HASH_MODE_HASH: $output = hash_hmac($this->hash, $text, $this->key, true); break; case CRYPT_HASH_MODE_INTERNAL: /* "Applications that use keys longer than B bytes will first hash the key using H and then use the resultant L byte string as the actual key to HMAC." -- http://tools.ietf.org/html/rfc2104#section-2 */ $key = strlen($this->key) > $this->b ? call_user_func($this->$hash, $this->key) : $this->key; $key = str_pad($key, $this->b, chr(0)); // step 1 $temp = $this->ipad ^ $key; // step 2 $temp .= $text; // step 3 $temp = call_user_func($this->hash, $temp); // step 4 $output = $this->opad ^ $key; // step 5 $output.= $temp; // step 6 $output = call_user_func($this->hash, $output); // step 7 } } else { switch ( $mode ) { case CRYPT_HASH_MODE_MHASH: $output = mhash($this->hash, $text); break; case CRYPT_HASH_MODE_HASH: $output = hash($this->hash, $text, true); break; case CRYPT_HASH_MODE_INTERNAL: $output = call_user_func($this->hash, $text); } } return substr($output, 0, $this->l); } /** * Returns the hash length (in bytes) * * @access private * @return Integer */ function getLength() { return $this->l; } /** * Wrapper for MD5 * * @access private * @param String $text */ function _md5($m) { return pack('H*', md5($m)); } /** * Wrapper for SHA1 * * @access private * @param String $text */ function _sha1($m) { return pack('H*', sha1($m)); } /** * Pure-PHP implementation of MD2 * * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}. * * @access private * @param String $text */ function _md2($m) { static $s = array( 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 ); // Step 1. Append Padding Bytes $pad = 16 - (strlen($m) & 0xF); $m.= str_repeat(chr($pad), $pad); $length = strlen($m); // Step 2. Append Checksum $c = str_repeat(chr(0), 16); $l = chr(0); for ($i = 0; $i < $length; $i+= 16) { for ($j = 0; $j < 16; $j++) { $c[$j] = chr($s[ord($m[$i + $j] ^ $l)]); $l = $c[$j]; } } $m.= $c; $length+= 16; // Step 3. Initialize MD Buffer $x = str_repeat(chr(0), 48); // Step 4. Process Message in 16-Byte Blocks for ($i = 0; $i < $length; $i+= 16) { for ($j = 0; $j < 16; $j++) { $x[$j + 16] = $m[$i + $j]; $x[$j + 32] = $x[$j + 16] ^ $x[$j]; } $t = chr(0); for ($j = 0; $j < 18; $j++) { for ($k = 0; $k < 48; $k++) { $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]); //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]); } $t = chr(ord($t) + $j); } } // Step 5. Output return substr($x, 0, 16); } /** * Pure-PHP implementation of SHA256 * * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}. * * @access private * @param String $text */ function _sha256($m) { if (extension_loaded('suhosin')) { return pack('H*', sha256($m)); } // Initialize variables $hash = array( 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ); // Initialize table of round constants // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311) static $k = array( 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ); // Pre-processing $length = strlen($m); // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64 $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F)); $m[$length] = chr(0x80); // we don't support hashing strings 512MB long $m.= pack('N2', 0, $length << 3); // Process the message in successive 512-bit chunks $chunks = str_split($m, 64); foreach ($chunks as $chunk) { $w = array(); for ($i = 0; $i < 16; $i++) { extract(unpack('Ntemp', $this->_string_shift($chunk, 4))); $w[] = $temp; } // Extend the sixteen 32-bit words into sixty-four 32-bit words for ($i = 16; $i < 64; $i++) { $s0 = $this->_rightRotate($w[$i - 15], 7) ^ $this->_rightRotate($w[$i - 15], 18) ^ $this->_rightShift( $w[$i - 15], 3); $s1 = $this->_rightRotate($w[$i - 2], 17) ^ $this->_rightRotate($w[$i - 2], 19) ^ $this->_rightShift( $w[$i - 2], 10); $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); } // Initialize hash value for this chunk list($a, $b, $c, $d, $e, $f, $g, $h) = $hash; // Main loop for ($i = 0; $i < 64; $i++) { $s0 = $this->_rightRotate($a, 2) ^ $this->_rightRotate($a, 13) ^ $this->_rightRotate($a, 22); $maj = ($a & $b) ^ ($a & $c) ^ ($b & $c); $t2 = $this->_add($s0, $maj); $s1 = $this->_rightRotate($e, 6) ^ $this->_rightRotate($e, 11) ^ $this->_rightRotate($e, 25); $ch = ($e & $f) ^ ($this->_not($e) & $g); $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]); $h = $g; $g = $f; $f = $e; $e = $this->_add($d, $t1); $d = $c; $c = $b; $b = $a; $a = $this->_add($t1, $t2); } // Add this chunk's hash to result so far $hash = array( $this->_add($hash[0], $a), $this->_add($hash[1], $b), $this->_add($hash[2], $c), $this->_add($hash[3], $d), $this->_add($hash[4], $e), $this->_add($hash[5], $f), $this->_add($hash[6], $g), $this->_add($hash[7], $h) ); } // Produce the final hash value (big-endian) return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]); } /** * Pure-PHP implementation of SHA384 and SHA512 * * @access private * @param String $text */ function _sha512($m) { if (!class_exists('Math_BigInteger')) { require_once('Math/BigInteger.php'); } static $init384, $init512, $k; if (!isset($k)) { // Initialize variables $init384 = array( // initial values for SHA384 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' ); $init512 = array( // initial values for SHA512 '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' ); for ($i = 0; $i < 8; $i++) { $init384[$i] = new Math_BigInteger($init384[$i], 16); $init384[$i]->setPrecision(64); $init512[$i] = new Math_BigInteger($init512[$i], 16); $init512[$i]->setPrecision(64); } // Initialize table of round constants // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409) $k = array( '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' ); for ($i = 0; $i < 80; $i++) { $k[$i] = new Math_BigInteger($k[$i], 16); } } $hash = $this->l == 48 ? $init384 : $init512; // Pre-processing $length = strlen($m); // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128 $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F)); $m[$length] = chr(0x80); // we don't support hashing strings 512MB long $m.= pack('N4', 0, 0, 0, $length << 3); // Process the message in successive 1024-bit chunks $chunks = str_split($m, 128); foreach ($chunks as $chunk) { $w = array(); for ($i = 0; $i < 16; $i++) { $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256); $temp->setPrecision(64); $w[] = $temp; } // Extend the sixteen 32-bit words into eighty 32-bit words for ($i = 16; $i < 80; $i++) { $temp = array( $w[$i - 15]->bitwise_rightRotate(1), $w[$i - 15]->bitwise_rightRotate(8), $w[$i - 15]->bitwise_rightShift(7) ); $s0 = $temp[0]->bitwise_xor($temp[1]); $s0 = $s0->bitwise_xor($temp[2]); $temp = array( $w[$i - 2]->bitwise_rightRotate(19), $w[$i - 2]->bitwise_rightRotate(61), $w[$i - 2]->bitwise_rightShift(6) ); $s1 = $temp[0]->bitwise_xor($temp[1]); $s1 = $s1->bitwise_xor($temp[2]); $w[$i] = $w[$i - 16]->copy(); $w[$i] = $w[$i]->add($s0); $w[$i] = $w[$i]->add($w[$i - 7]); $w[$i] = $w[$i]->add($s1); } // Initialize hash value for this chunk $a = $hash[0]->copy(); $b = $hash[1]->copy(); $c = $hash[2]->copy(); $d = $hash[3]->copy(); $e = $hash[4]->copy(); $f = $hash[5]->copy(); $g = $hash[6]->copy(); $h = $hash[7]->copy(); // Main loop for ($i = 0; $i < 80; $i++) { $temp = array( $a->bitwise_rightRotate(28), $a->bitwise_rightRotate(34), $a->bitwise_rightRotate(39) ); $s0 = $temp[0]->bitwise_xor($temp[1]); $s0 = $s0->bitwise_xor($temp[2]); $temp = array( $a->bitwise_and($b), $a->bitwise_and($c), $b->bitwise_and($c) ); $maj = $temp[0]->bitwise_xor($temp[1]); $maj = $maj->bitwise_xor($temp[2]); $t2 = $s0->add($maj); $temp = array( $e->bitwise_rightRotate(14), $e->bitwise_rightRotate(18), $e->bitwise_rightRotate(41) ); $s1 = $temp[0]->bitwise_xor($temp[1]); $s1 = $s1->bitwise_xor($temp[2]); $temp = array( $e->bitwise_and($f), $g->bitwise_and($e->bitwise_not()) ); $ch = $temp[0]->bitwise_xor($temp[1]); $t1 = $h->add($s1); $t1 = $t1->add($ch); $t1 = $t1->add($k[$i]); $t1 = $t1->add($w[$i]); $h = $g->copy(); $g = $f->copy(); $f = $e->copy(); $e = $d->add($t1); $d = $c->copy(); $c = $b->copy(); $b = $a->copy(); $a = $t1->add($t2); } // Add this chunk's hash to result so far $hash = array( $hash[0]->add($a), $hash[1]->add($b), $hash[2]->add($c), $hash[3]->add($d), $hash[4]->add($e), $hash[5]->add($f), $hash[6]->add($g), $hash[7]->add($h) ); } // Produce the final hash value (big-endian) // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here) $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . $hash[4]->toBytes() . $hash[5]->toBytes(); if ($this->l != 48) { $temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); } return $temp; } /** * Right Rotate * * @access private * @param Integer $int * @param Integer $amt * @see _sha256() * @return Integer */ function _rightRotate($int, $amt) { $invamt = 32 - $amt; $mask = (1 << $invamt) - 1; return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask); } /** * Right Shift * * @access private * @param Integer $int * @param Integer $amt * @see _sha256() * @return Integer */ function _rightShift($int, $amt) { $mask = (1 << (32 - $amt)) - 1; return ($int >> $amt) & $mask; } /** * Not * * @access private * @param Integer $int * @see _sha256() * @return Integer */ function _not($int) { return ~$int & 0xFFFFFFFF; } /** * Add * * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster. * * @param String $string * @param optional Integer $index * @return String * @see _sha256() * @access private */ function _add() { static $mod; if (!isset($mod)) { $mod = pow(2, 32); } $result = 0; $arguments = func_get_args(); foreach ($arguments as $argument) { $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument; } return fmod($result, $mod); } /** * String Shift * * Inspired by array_shift * * @param String $string * @param optional Integer $index * @return String * @access private */ function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } }debian/db-update/v20111210/Crypt/RSA.php0000644000000000000000000021422212267045571014363 0ustar * createKey()); * * $plaintext = 'terrafrost'; * * $rsa->loadKey($privatekey); * $ciphertext = $rsa->encrypt($plaintext); * * $rsa->loadKey($publickey); * echo $rsa->decrypt($ciphertext); * ?> * * * Here's an example of how to create signatures and verify signatures with this library: * * createKey()); * * $plaintext = 'terrafrost'; * * $rsa->loadKey($privatekey); * $signature = $rsa->sign($plaintext); * * $rsa->loadKey($publickey); * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified'; * ?> * * * LICENSE: This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * @category Crypt * @package Crypt_RSA * @author Jim Wigginton * @copyright MMIX Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version $Id: RSA.php,v 1.19 2010/09/12 21:58:54 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ /** * Include Math_BigInteger */ require_once('Math/BigInteger.php'); /** * Include Crypt_Random */ require_once('Crypt/Random.php'); /** * Include Crypt_Hash */ require_once('Crypt/Hash.php'); /**#@+ * @access public * @see Crypt_RSA::encrypt() * @see Crypt_RSA::decrypt() */ /** * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding} * (OAEP) for encryption / decryption. * * Uses sha1 by default. * * @see Crypt_RSA::setHash() * @see Crypt_RSA::setMGFHash() */ define('CRYPT_RSA_ENCRYPTION_OAEP', 1); /** * Use PKCS#1 padding. * * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards * compatability with protocols (like SSH-1) written before OAEP's introduction. */ define('CRYPT_RSA_ENCRYPTION_PKCS1', 2); /**#@-*/ /**#@+ * @access public * @see Crypt_RSA::sign() * @see Crypt_RSA::verify() * @see Crypt_RSA::setHash() */ /** * Use the Probabilistic Signature Scheme for signing * * Uses sha1 by default. * * @see Crypt_RSA::setSaltLength() * @see Crypt_RSA::setMGFHash() */ define('CRYPT_RSA_SIGNATURE_PSS', 1); /** * Use the PKCS#1 scheme by default. * * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards * compatability with protocols (like SSH-2) written before PSS's introduction. */ define('CRYPT_RSA_SIGNATURE_PKCS1', 2); /**#@-*/ /**#@+ * @access private * @see Crypt_RSA::createKey() */ /** * ASN1 Integer */ define('CRYPT_RSA_ASN1_INTEGER', 2); /** * ASN1 Sequence (with the constucted bit set) */ define('CRYPT_RSA_ASN1_SEQUENCE', 48); /**#@-*/ /**#@+ * @access private * @see Crypt_RSA::Crypt_RSA() */ /** * To use the pure-PHP implementation */ define('CRYPT_RSA_MODE_INTERNAL', 1); /** * To use the OpenSSL library * * (if enabled; otherwise, the internal implementation will be used) */ define('CRYPT_RSA_MODE_OPENSSL', 2); /**#@-*/ /**#@+ * @access public * @see Crypt_RSA::createKey() * @see Crypt_RSA::setPrivateKeyFormat() */ /** * PKCS#1 formatted private key * * Used by OpenSSH */ define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0); /**#@-*/ /**#@+ * @access public * @see Crypt_RSA::createKey() * @see Crypt_RSA::setPublicKeyFormat() */ /** * Raw public key * * An array containing two Math_BigInteger objects. * * The exponent can be indexed with any of the following: * * 0, e, exponent, publicExponent * * The modulus can be indexed with any of the following: * * 1, n, modulo, modulus */ define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 1); /** * PKCS#1 formatted public key */ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 2); /** * OpenSSH formatted public key * * Place in $HOME/.ssh/authorized_keys */ define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 3); /**#@-*/ /** * Pure-PHP PKCS#1 compliant implementation of RSA. * * @author Jim Wigginton * @version 0.1.0 * @access public * @package Crypt_RSA */ class Crypt_RSA { /** * Precomputed Zero * * @var Array * @access private */ var $zero; /** * Precomputed One * * @var Array * @access private */ var $one; /** * Private Key Format * * @var Integer * @access private */ var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1; /** * Public Key Format * * @var Integer * @access public */ var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1; /** * Modulus (ie. n) * * @var Math_BigInteger * @access private */ var $modulus; /** * Modulus length * * @var Math_BigInteger * @access private */ var $k; /** * Exponent (ie. e or d) * * @var Math_BigInteger * @access private */ var $exponent; /** * Primes for Chinese Remainder Theorem (ie. p and q) * * @var Array * @access private */ var $primes; /** * Exponents for Chinese Remainder Theorem (ie. dP and dQ) * * @var Array * @access private */ var $exponents; /** * Coefficients for Chinese Remainder Theorem (ie. qInv) * * @var Array * @access private */ var $coefficients; /** * Hash name * * @var String * @access private */ var $hashName; /** * Hash function * * @var Crypt_Hash * @access private */ var $hash; /** * Length of hash function output * * @var Integer * @access private */ var $hLen; /** * Length of salt * * @var Integer * @access private */ var $sLen; /** * Hash function for the Mask Generation Function * * @var Crypt_Hash * @access private */ var $mgfHash; /** * Length of MGF hash function output * * @var Integer * @access private */ var $mgfHLen; /** * Encryption mode * * @var Integer * @access private */ var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP; /** * Signature mode * * @var Integer * @access private */ var $signatureMode = CRYPT_RSA_SIGNATURE_PSS; /** * Public Exponent * * @var Mixed * @access private */ var $publicExponent = false; /** * Password * * @var String * @access private */ var $password = ''; /** * The constructor * * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late. * * @return Crypt_RSA * @access public */ function Crypt_RSA() { if ( !defined('CRYPT_RSA_MODE') ) { switch (true) { //case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='): // define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL); // break; default: define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); } } $this->zero = new Math_BigInteger(); $this->one = new Math_BigInteger(1); $this->hash = new Crypt_Hash('sha1'); $this->hLen = $this->hash->getLength(); $this->hashName = 'sha1'; $this->mgfHash = new Crypt_Hash('sha1'); $this->mgfHLen = $this->mgfHash->getLength(); } /** * Create public / private key pair * * Returns an array with the following three elements: * - 'privatekey': The private key. * - 'publickey': The public key. * - 'partialkey': A partially computed key (if the execution time exceeded $timeout). * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing. * * @access public * @param optional Integer $bits * @param optional Integer $timeout * @param optional Math_BigInteger $p */ function createKey($bits = 1024, $timeout = false, $partial = array()) { if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) { $rsa = openssl_pkey_new(array('private_key_bits' => $bits)); openssl_pkey_export($rsa, $privatekey); $publickey = openssl_pkey_get_details($rsa); $publickey = $publickey['key']; if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) { $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1))); $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1))); } return array( 'privatekey' => $privatekey, 'publickey' => $publickey, 'partialkey' => false ); } static $e; if (!isset($e)) { if (!defined('CRYPT_RSA_EXPONENT')) { // http://en.wikipedia.org/wiki/65537_%28number%29 define('CRYPT_RSA_EXPONENT', '65537'); } if (!defined('CRYPT_RSA_COMMENT')) { define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key'); } // per , this number ought not result in primes smaller // than 256 bits. if (!defined('CRYPT_RSA_SMALLEST_PRIME')) { define('CRYPT_RSA_SMALLEST_PRIME', 4096); } $e = new Math_BigInteger(CRYPT_RSA_EXPONENT); } extract($this->_generateMinMax($bits)); $absoluteMin = $min; $temp = $bits >> 1; if ($temp > CRYPT_RSA_SMALLEST_PRIME) { $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME); $temp = CRYPT_RSA_SMALLEST_PRIME; } else { $num_primes = 2; } extract($this->_generateMinMax($temp + $bits % $temp)); $finalMax = $max; extract($this->_generateMinMax($temp)); $generator = new Math_BigInteger(); $generator->setRandomGenerator('crypt_random'); $n = $this->one->copy(); if (!empty($partial)) { extract(unserialize($partial)); } else { $exponents = $coefficients = $primes = array(); $lcm = array( 'top' => $this->one->copy(), 'bottom' => false ); } $start = time(); $i0 = count($primes) + 1; do { for ($i = $i0; $i <= $num_primes; $i++) { if ($timeout !== false) { $timeout-= time() - $start; $start = time(); if ($timeout <= 0) { return array( 'privatekey' => '', 'publickey' => '', 'partialkey' => serialize(array( 'primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents )) ); } } if ($i == $num_primes) { list($min, $temp) = $absoluteMin->divide($n); if (!$temp->equals($this->zero)) { $min = $min->add($this->one); // ie. ceil() } $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout); } else { $primes[$i] = $generator->randomPrime($min, $max, $timeout); } if ($primes[$i] === false) { // if we've reached the timeout if (count($primes) > 1) { $partialkey = ''; } else { array_pop($primes); $partialkey = serialize(array( 'primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents )); } return array( 'privatekey' => '', 'publickey' => '', 'partialkey' => $partialkey ); } // the first coefficient is calculated differently from the rest // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1]) if ($i > 2) { $coefficients[$i] = $n->modInverse($primes[$i]); } $n = $n->multiply($primes[$i]); $temp = $primes[$i]->subtract($this->one); // textbook RSA implementations use Euler's totient function instead of the least common multiple. // see http://en.wikipedia.org/wiki/Euler%27s_totient_function $lcm['top'] = $lcm['top']->multiply($temp); $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); $exponents[$i] = $e->modInverse($temp); } list($lcm) = $lcm['top']->divide($lcm['bottom']); $gcd = $lcm->gcd($e); $i0 = 1; } while (!$gcd->equals($this->one)); $d = $e->modInverse($lcm); $coefficients[2] = $primes[2]->modInverse($primes[1]); // from : // RSAPrivateKey ::= SEQUENCE { // version Version, // modulus INTEGER, -- n // publicExponent INTEGER, -- e // privateExponent INTEGER, -- d // prime1 INTEGER, -- p // prime2 INTEGER, -- q // exponent1 INTEGER, -- d mod (p-1) // exponent2 INTEGER, -- d mod (q-1) // coefficient INTEGER, -- (inverse of q) mod p // otherPrimeInfos OtherPrimeInfos OPTIONAL // } return array( 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients), 'publickey' => $this->_convertPublicKey($n, $e), 'partialkey' => false ); } /** * Convert a private key to the appropriate format. * * @access private * @see setPrivateKeyFormat() * @param String $RSAPrivateKey * @return String */ function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) { $num_primes = count($primes); $raw = array( 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi 'modulus' => $n->toBytes(true), 'publicExponent' => $e->toBytes(true), 'privateExponent' => $d->toBytes(true), 'prime1' => $primes[1]->toBytes(true), 'prime2' => $primes[2]->toBytes(true), 'exponent1' => $exponents[1]->toBytes(true), 'exponent2' => $exponents[2]->toBytes(true), 'coefficient' => $coefficients[2]->toBytes(true) ); // if the format in question does not support multi-prime rsa and multi-prime rsa was used, // call _convertPublicKey() instead. switch ($this->privateKeyFormat) { default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1 $components = array(); foreach ($raw as $name => $value) { $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value); } $RSAPrivateKey = implode('', $components); if ($num_primes > 2) { $OtherPrimeInfos = ''; for ($i = 3; $i <= $num_primes; $i++) { // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo // // OtherPrimeInfo ::= SEQUENCE { // prime INTEGER, -- ri // exponent INTEGER, -- di // coefficient INTEGER -- ti // } $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true)); $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true)); $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true)); $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo); } $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos); } $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); if (!empty($this->password)) { $iv = $this->_random(8); $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); if (!class_exists('Crypt_TripleDES')) { require_once('Crypt/TripleDES.php'); } $des = new Crypt_TripleDES(); $des->setKey($symkey); $des->setIV($iv); $iv = strtoupper(bin2hex($iv)); $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . "Proc-Type: 4,ENCRYPTED\r\n" . "DEK-Info: DES-EDE3-CBC,$iv\r\n" . "\r\n" . chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) . '-----END RSA PRIVATE KEY-----'; } else { $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . chunk_split(base64_encode($RSAPrivateKey)) . '-----END RSA PRIVATE KEY-----'; } return $RSAPrivateKey; } } /** * Convert a public key to the appropriate format * * @access private * @see setPublicKeyFormat() * @param String $RSAPrivateKey * @return String */ function _convertPublicKey($n, $e) { $modulus = $n->toBytes(true); $publicExponent = $e->toBytes(true); switch ($this->publicKeyFormat) { case CRYPT_RSA_PUBLIC_FORMAT_RAW: return array('e' => $e->copy(), 'n' => $n->copy()); case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: // from : // string "ssh-rsa" // mpint e // mpint n $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT; return $RSAPublicKey; default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1 // from : // RSAPublicKey ::= SEQUENCE { // modulus INTEGER, -- n // publicExponent INTEGER -- e // } $components = array( 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus), 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent) ); $RSAPublicKey = pack('Ca*a*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), $components['modulus'], $components['publicExponent'] ); $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(base64_encode($RSAPublicKey)) . '-----END PUBLIC KEY-----'; return $RSAPublicKey; } } /** * Break a public or private key down into its constituant components * * @access private * @see _convertPublicKey() * @see _convertPrivateKey() * @param String $key * @param Integer $type * @return Array */ function _parseKey($key, $type) { switch ($type) { case CRYPT_RSA_PUBLIC_FORMAT_RAW: if (!is_array($key)) { return false; } $components = array(); switch (true) { case isset($key['e']): $components['publicExponent'] = $key['e']->copy(); break; case isset($key['exponent']): $components['publicExponent'] = $key['exponent']->copy(); break; case isset($key['publicExponent']): $components['publicExponent'] = $key['publicExponent']->copy(); break; case isset($key[0]): $components['publicExponent'] = $key[0]->copy(); } switch (true) { case isset($key['n']): $components['modulus'] = $key['n']->copy(); break; case isset($key['modulo']): $components['modulus'] = $key['modulo']->copy(); break; case isset($key['modulus']): $components['modulus'] = $key['modulus']->copy(); break; case isset($key[1]): $components['modulus'] = $key[1]->copy(); } return $components; case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: case CRYPT_RSA_PUBLIC_FORMAT_PKCS1: /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here: http://tools.ietf.org/html/rfc1421#section-4.6.1.1 http://tools.ietf.org/html/rfc1421#section-4.6.1.3 DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell. DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's own implementation. ie. the implementation *is* the standard and any bugs that may exist in that implementation are part of the standard, as well. * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { $iv = pack('H*', trim($matches[2])); $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key); $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false; if ($ciphertext === false) { $ciphertext = $key; } switch ($matches[1]) { case 'AES-128-CBC': if (!class_exists('Crypt_AES')) { require_once('Crypt/AES.php'); } $symkey = substr($symkey, 0, 16); break; case 'DES-EDE3-CFB': if (!class_exists('Crypt_TripleDES')) { require_once('Crypt/TripleDES.php'); } $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB); break; case 'DES-EDE3-CBC': if (!class_exists('Crypt_TripleDES')) { require_once('Crypt/TripleDES.php'); } $crypto = new Crypt_TripleDES(); break; case 'DES-CBC': if (!class_exists('Crypt_DES')) { require_once('Crypt/DES.php'); } $crypto = new Crypt_DES(); break; default: return false; } $crypto->setKey($symkey); $crypto->setIV($iv); $decoded = $crypto->decrypt($ciphertext); } else { $decoded = preg_replace('#-.+-|[\r\n]#', '', $key); $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false; } if ($decoded !== false) { $key = $decoded; } $components = array(); if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } if ($this->_decodeLength($key) != strlen($key)) { return false; } $tag = ord($this->_string_shift($key)); if ($tag == CRYPT_RSA_ASN1_SEQUENCE) { /* intended for keys for which OpenSSL's asn1parse returns the following: 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING */ $this->_string_shift($key, $this->_decodeLength($key)); $this->_string_shift($key); // skip over the BIT STRING tag $this->_decodeLength($key); // skip over the BIT STRING length // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of // unused bits in teh final subsequent octet. The number shall be in the range zero to seven." // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2) $this->_string_shift($key); if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } if ($this->_decodeLength($key) != strlen($key)) { return false; } $tag = ord($this->_string_shift($key)); } if ($tag != CRYPT_RSA_ASN1_INTEGER) { return false; } /* We peek a little forwards, if an sequence follows the integer field, there is some additional padding we need to strip */ if (ord(substr($key, 2, 1)) == CRYPT_RSA_ASN1_SEQUENCE) { /* intended for keys for which openssl's asn1parse returns the following: 0:d=0 hl=4 l= 631 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :00 7:d=1 hl=2 l= 13 cons: SEQUENCE 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 20:d=2 hl=2 l= 0 prim: NULL 22:d=1 hl=4 l= 609 prim: OCTET STRING [HEX DUMP] */ $tag = ord($this->_string_shift($key, $this->_decodeLength($key))); /* Read the sequence with the object in it */ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } /* skip over the rsaEncryption object and over the trailing NULL */ $encLength = $this->_decodeLength($key); $this->_string_shift($key, $encLength); if (ord($this->_string_shift($key)) != 4) { /* skip over the OCTET STRING tag */ return false; } # if $this->_decodeLength($key); // skip over the OCTET STRING length /* Inside this package we will find another ASN1 sequence and length, because at this time in the parser, it is expected to be beyond this, skip it */ $this->_string_shift($key); // skip over the sequence tag $this->_decodeLength($key); // skip over the sequence length $tag = ord($this->_string_shift($key)); } # if $length = $this->_decodeLength($key); $temp = $this->_string_shift($key, $length); if (strlen($temp) != 1 || ord($temp) > 2) { $components['modulus'] = new Math_BigInteger($temp, -256); $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER $length = $this->_decodeLength($key); $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); return $components; } if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) { return false; } $length = $this->_decodeLength($key); $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256)); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256)); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256)); if (!empty($key)) { if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } $this->_decodeLength($key); while (!empty($key)) { if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } $this->_decodeLength($key); $key = substr($key, 1); $length = $this->_decodeLength($key); $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); } } return $components; case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key)); if ($key === false) { return false; } $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa"; extract(unpack('Nlength', $this->_string_shift($key, 4))); $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256); extract(unpack('Nlength', $this->_string_shift($key, 4))); $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256); if ($cleanup && strlen($key)) { extract(unpack('Nlength', $this->_string_shift($key, 4))); return array( 'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256), 'publicExponent' => $modulus ); } else { return array( 'modulus' => $modulus, 'publicExponent' => $publicExponent ); } } } /** * Loads a public or private key * * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) * * @access public * @param String $key * @param Integer $type optional */ function loadKey($key, $type = CRYPT_RSA_PRIVATE_FORMAT_PKCS1) { $components = $this->_parseKey($key, $type); if ($components === false) { return false; } $this->modulus = $components['modulus']; $this->k = strlen($this->modulus->toBytes()); $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; if (isset($components['primes'])) { $this->primes = $components['primes']; $this->exponents = $components['exponents']; $this->coefficients = $components['coefficients']; $this->publicExponent = $components['publicExponent']; } else { $this->primes = array(); $this->exponents = array(); $this->coefficients = array(); $this->publicExponent = false; } return true; } /** * Sets the password * * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false. * Or rather, pass in $password such that empty($password) is true. * * @see createKey() * @see loadKey() * @access public * @param String $password */ function setPassword($password) { $this->password = $password; } /** * Defines the public key * * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public * exponent this won't work unless you manually add the public exponent. * * Do note that when a new key is loaded the index will be cleared. * * Returns true on success, false on failure * * @see getPublicKey() * @access public * @param String $key * @param Integer $type optional * @return Boolean */ function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { $components = $this->_parseKey($key, $type); if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { user_error('Trying to load a public key? Use loadKey() instead. It\'s called loadKey() and not loadPrivateKey() for a reason.', E_USER_NOTICE); return false; } $this->publicExponent = $components['publicExponent']; return true; } /** * Returns the public key * * The public key is only returned under two circumstances - if the private key had the public key embedded within it * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this * function won't return it since this library, for the most part, doesn't distinguish between public and private keys. * * @see getPublicKey() * @access public * @param String $key * @param Integer $type optional */ function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { if (empty($this->modulus) || empty($this->publicExponent)) { return false; } $oldFormat = $this->publicKeyFormat; $this->publicKeyFormat = $type; $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent); $this->publicKeyFormat = $oldFormat; return $temp; } /** * Generates the smallest and largest numbers requiring $bits bits * * @access private * @param Integer $bits * @return Array */ function _generateMinMax($bits) { $bytes = $bits >> 3; $min = str_repeat(chr(0), $bytes); $max = str_repeat(chr(0xFF), $bytes); $msb = $bits & 7; if ($msb) { $min = chr(1 << ($msb - 1)) . $min; $max = chr((1 << $msb) - 1) . $max; } else { $min[0] = chr(0x80); } return array( 'min' => new Math_BigInteger($min, 256), 'max' => new Math_BigInteger($max, 256) ); } /** * DER-decode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information. * * @access private * @param String $string * @return Integer */ function _decodeLength(&$string) { $length = ord($this->_string_shift($string)); if ( $length & 0x80 ) { // definite length, long form $length&= 0x7F; $temp = $this->_string_shift($string, $length); list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)); } return $length; } /** * DER-encode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information. * * @access private * @param Integer $length * @return String */ function _encodeLength($length) { if ($length <= 0x7F) { return chr($length); } $temp = ltrim(pack('N', $length), chr(0)); return pack('Ca*', 0x80 | strlen($temp), $temp); } /** * String Shift * * Inspired by array_shift * * @param String $string * @param optional Integer $index * @return String * @access private */ function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } /** * Determines the private key format * * @see createKey() * @access public * @param Integer $format */ function setPrivateKeyFormat($format) { $this->privateKeyFormat = $format; } /** * Determines the public key format * * @see createKey() * @access public * @param Integer $format */ function setPublicKeyFormat($format) { $this->publicKeyFormat = $format; } /** * Determines which hashing function should be used * * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and * decryption. If $hash isn't supported, sha1 is used. * * @access public * @param String $hash */ function setHash($hash) { // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. switch ($hash) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': $this->hash = new Crypt_Hash($hash); $this->hashName = $hash; break; default: $this->hash = new Crypt_Hash('sha1'); $this->hashName = 'sha1'; } $this->hLen = $this->hash->getLength(); } /** * Determines which hashing function should be used for the mask generation function * * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's * best if Hash and MGFHash are set to the same thing this is not a requirement. * * @access public * @param String $hash */ function setMGFHash($hash) { // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. switch ($hash) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': $this->mgfHash = new Crypt_Hash($hash); break; default: $this->mgfHash = new Crypt_Hash('sha1'); } $this->mgfHLen = $this->mgfHash->getLength(); } /** * Determines the salt length * * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}: * * Typical salt lengths in octets are hLen (the length of the output * of the hash function Hash) and 0. * * @access public * @param Integer $format */ function setSaltLength($sLen) { $this->sLen = $sLen; } /** * Generates a random string x bytes long * * @access public * @param Integer $bytes * @param optional Integer $nonzero * @return String */ function _random($bytes, $nonzero = false) { $temp = ''; if ($nonzero) { for ($i = 0; $i < $bytes; $i++) { $temp.= chr(crypt_random(1, 255)); } } else { $ints = ($bytes + 1) >> 2; for ($i = 0; $i < $ints; $i++) { $temp.= pack('N', crypt_random()); } $temp = substr($temp, 0, $bytes); } return $temp; } /** * Integer-to-Octet-String primitive * * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}. * * @access private * @param Math_BigInteger $x * @param Integer $xLen * @return String */ function _i2osp($x, $xLen) { $x = $x->toBytes(); if (strlen($x) > $xLen) { user_error('Integer too large', E_USER_NOTICE); return false; } return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); } /** * Octet-String-to-Integer primitive * * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}. * * @access private * @param String $x * @return Math_BigInteger */ function _os2ip($x) { return new Math_BigInteger($x, 256); } /** * Exponentiate with or without Chinese Remainder Theorem * * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}. * * @access private * @param Math_BigInteger $x * @return Math_BigInteger */ function _exponentiate($x) { if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) { return $x->modPow($this->exponent, $this->modulus); } $num_primes = count($this->primes); if (defined('CRYPT_RSA_DISABLE_BLINDING')) { $m_i = array( 1 => $x->modPow($this->exponents[1], $this->primes[1]), 2 => $x->modPow($this->exponents[2], $this->primes[2]) ); $h = $m_i[1]->subtract($m_i[2]); $h = $h->multiply($this->coefficients[2]); list(, $h) = $h->divide($this->primes[1]); $m = $m_i[2]->add($h->multiply($this->primes[2])); $r = $this->primes[1]; for ($i = 3; $i <= $num_primes; $i++) { $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->multiply($this->primes[$i - 1]); $h = $m_i->subtract($m); $h = $h->multiply($this->coefficients[$i]); list(, $h) = $h->divide($this->primes[$i]); $m = $m->add($r->multiply($h)); } } else { $smallest = $this->primes[1]; for ($i = 2; $i <= $num_primes; $i++) { if ($smallest->compare($this->primes[$i]) > 0) { $smallest = $this->primes[$i]; } } $one = new Math_BigInteger(1); $one->setRandomGenerator('crypt_random'); $r = $one->random($one, $smallest->subtract($one)); $m_i = array( 1 => $this->_blind($x, $r, 1), 2 => $this->_blind($x, $r, 2) ); $h = $m_i[1]->subtract($m_i[2]); $h = $h->multiply($this->coefficients[2]); list(, $h) = $h->divide($this->primes[1]); $m = $m_i[2]->add($h->multiply($this->primes[2])); $r = $this->primes[1]; for ($i = 3; $i <= $num_primes; $i++) { $m_i = $this->_blind($x, $r, $i); $r = $r->multiply($this->primes[$i - 1]); $h = $m_i->subtract($m); $h = $h->multiply($this->coefficients[$i]); list(, $h) = $h->divide($this->primes[$i]); $m = $m->add($r->multiply($h)); } } return $m; } /** * Performs RSA Blinding * * Protects against timing attacks by employing RSA Blinding. * Returns $x->modPow($this->exponents[$i], $this->primes[$i]) * * @access private * @param Math_BigInteger $x * @param Math_BigInteger $r * @param Integer $i * @return Math_BigInteger */ function _blind($x, $r, $i) { $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); $x = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->modInverse($this->primes[$i]); $x = $x->multiply($r); list(, $x) = $x->divide($this->primes[$i]); return $x; } /** * RSAEP * * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}. * * @access private * @param Math_BigInteger $m * @return Math_BigInteger */ function _rsaep($m) { if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { user_error('Message representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($m); } /** * RSADP * * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}. * * @access private * @param Math_BigInteger $c * @return Math_BigInteger */ function _rsadp($c) { if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) { user_error('Ciphertext representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($c); } /** * RSASP1 * * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}. * * @access private * @param Math_BigInteger $m * @return Math_BigInteger */ function _rsasp1($m) { if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { user_error('Message representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($m); } /** * RSAVP1 * * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}. * * @access private * @param Math_BigInteger $s * @return Math_BigInteger */ function _rsavp1($s) { if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) { user_error('Signature representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($s); } /** * MGF1 * * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}. * * @access private * @param String $mgfSeed * @param Integer $mgfLen * @return String */ function _mgf1($mgfSeed, $maskLen) { // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output. $t = ''; $count = ceil($maskLen / $this->mgfHLen); for ($i = 0; $i < $count; $i++) { $c = pack('N', $i); $t.= $this->mgfHash->hash($mgfSeed . $c); } return substr($t, 0, $maskLen); } /** * RSAES-OAEP-ENCRYPT * * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}. * * @access private * @param String $m * @param String $l * @return String */ function _rsaes_oaep_encrypt($m, $l = '') { $mLen = strlen($m); // Length checking // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error // be output. if ($mLen > $this->k - 2 * $this->hLen - 2) { user_error('Message too long', E_USER_NOTICE); return false; } // EME-OAEP encoding $lHash = $this->hash->hash($l); $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2); $db = $lHash . $ps . chr(1) . $m; $seed = $this->_random($this->hLen); $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); $maskedDB = $db ^ $dbMask; $seedMask = $this->_mgf1($maskedDB, $this->hLen); $maskedSeed = $seed ^ $seedMask; $em = chr(0) . $maskedSeed . $maskedDB; // RSA encryption $m = $this->_os2ip($em); $c = $this->_rsaep($m); $c = $this->_i2osp($c, $this->k); // Output the ciphertext C return $c; } /** * RSAES-OAEP-DECRYPT * * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2: * * Note. Care must be taken to ensure that an opponent cannot * distinguish the different error conditions in Step 3.g, whether by * error message or timing, or, more generally, learn partial * information about the encoded message EM. Otherwise an opponent may * be able to obtain useful information about the decryption of the * ciphertext C, leading to a chosen-ciphertext attack such as the one * observed by Manger [36]. * * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}: * * Both the encryption and the decryption operations of RSAES-OAEP take * the value of a label L as input. In this version of PKCS #1, L is * the empty string; other uses of the label are outside the scope of * this document. * * @access private * @param String $c * @param String $l * @return String */ function _rsaes_oaep_decrypt($c, $l = '') { // Length checking // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error // be output. if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { user_error('Decryption error', E_USER_NOTICE); return false; } // RSA decryption $c = $this->_os2ip($c); $m = $this->_rsadp($c); if ($m === false) { user_error('Decryption error', E_USER_NOTICE); return false; } $em = $this->_i2osp($m, $this->k); // EME-OAEP decoding $lHash = $this->hash->hash($l); $y = ord($em[0]); $maskedSeed = substr($em, 1, $this->hLen); $maskedDB = substr($em, $this->hLen + 1); $seedMask = $this->_mgf1($maskedDB, $this->hLen); $seed = $maskedSeed ^ $seedMask; $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $lHash2 = substr($db, 0, $this->hLen); $m = substr($db, $this->hLen); if ($lHash != $lHash2) { user_error('Decryption error', E_USER_NOTICE); return false; } $m = ltrim($m, chr(0)); if (ord($m[0]) != 1) { user_error('Decryption error', E_USER_NOTICE); return false; } // Output the message M return substr($m, 1); } /** * RSAES-PKCS1-V1_5-ENCRYPT * * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}. * * @access private * @param String $m * @return String */ function _rsaes_pkcs1_v1_5_encrypt($m) { $mLen = strlen($m); // Length checking if ($mLen > $this->k - 11) { user_error('Message too long', E_USER_NOTICE); return false; } // EME-PKCS1-v1_5 encoding $ps = $this->_random($this->k - $mLen - 3, true); $em = chr(0) . chr(2) . $ps . chr(0) . $m; // RSA encryption $m = $this->_os2ip($em); $c = $this->_rsaep($m); $c = $this->_i2osp($c, $this->k); // Output the ciphertext C return $c; } /** * RSAES-PKCS1-V1_5-DECRYPT * * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}. * * For compatability purposes, this function departs slightly from the description given in RFC3447. * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed * to be 2 regardless of which key is used. for compatability purposes, we'll just check to make sure the * second byte is 2 or less. If it is, we'll accept the decrypted string as valid. * * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but * not private key encrypted ciphertext's. * * @access private * @param String $c * @return String */ function _rsaes_pkcs1_v1_5_decrypt($c) { // Length checking if (strlen($c) != $this->k) { // or if k < 11 user_error('Decryption error', E_USER_NOTICE); return false; } // RSA decryption $c = $this->_os2ip($c); $m = $this->_rsadp($c); if ($m === false) { user_error('Decryption error', E_USER_NOTICE); return false; } $em = $this->_i2osp($m, $this->k); // EME-PKCS1-v1_5 decoding if (ord($em[0]) != 0 || ord($em[1]) > 2) { user_error('Decryption error', E_USER_NOTICE); return false; } $ps = substr($em, 2, strpos($em, chr(0), 2) - 2); $m = substr($em, strlen($ps) + 3); if (strlen($ps) < 8) { user_error('Decryption error', E_USER_NOTICE); return false; } // Output M return $m; } /** * EMSA-PSS-ENCODE * * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}. * * @access private * @param String $m * @param Integer $emBits */ function _emsa_pss_encode($m, $emBits) { // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error // be output. $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8) $sLen = $this->sLen == false ? $this->hLen : $this->sLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { user_error('Encoding error', E_USER_NOTICE); return false; } $salt = $this->_random($sLen); $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h = $this->hash->hash($m2); $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2); $db = $ps . chr(1) . $salt; $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); $maskedDB = $db ^ $dbMask; $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0]; $em = $maskedDB . $h . chr(0xBC); return $em; } /** * EMSA-PSS-VERIFY * * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}. * * @access private * @param String $m * @param String $em * @param Integer $emBits * @return String */ function _emsa_pss_verify($m, $em, $emBits) { // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error // be output. $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8); $sLen = $this->sLen == false ? $this->hLen : $this->sLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { return false; } if ($em[strlen($em) - 1] != chr(0xBC)) { return false; } $maskedDB = substr($em, 0, $em - $this->hLen - 1); $h = substr($em, $em - $this->hLen - 1, $this->hLen); $temp = chr(0xFF << ($emBits & 7)); if ((~$maskedDB[0] & $temp) != $temp) { return false; } $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; $temp = $emLen - $this->hLen - $sLen - 2; if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) { return false; } $salt = substr($db, $temp + 1); // should be $sLen long $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h2 = $this->hash->hash($m2); return $h == $h2; } /** * RSASSA-PSS-SIGN * * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}. * * @access private * @param String $m * @return String */ function _rsassa_pss_sign($m) { // EMSA-PSS encoding $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1); // RSA signature $m = $this->_os2ip($em); $s = $this->_rsasp1($m); $s = $this->_i2osp($s, $this->k); // Output the signature S return $s; } /** * RSASSA-PSS-VERIFY * * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}. * * @access private * @param String $m * @param String $s * @return String */ function _rsassa_pss_verify($m, $s) { // Length checking if (strlen($s) != $this->k) { user_error('Invalid signature', E_USER_NOTICE); return false; } // RSA verification $modBits = 8 * $this->k; $s2 = $this->_os2ip($s); $m2 = $this->_rsavp1($s2); if ($m2 === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } $em = $this->_i2osp($m2, $modBits >> 3); if ($em === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } // EMSA-PSS verification return $this->_emsa_pss_verify($m, $em, $modBits - 1); } /** * EMSA-PKCS1-V1_5-ENCODE * * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}. * * @access private * @param String $m * @param Integer $emLen * @return String */ function _emsa_pkcs1_v1_5_encode($m, $emLen) { $h = $this->hash->hash($m); if ($h === false) { return false; } // see http://tools.ietf.org/html/rfc3447#page-43 switch ($this->hashName) { case 'md2': $t = pack('H*', '3020300c06082a864886f70d020205000410'); break; case 'md5': $t = pack('H*', '3020300c06082a864886f70d020505000410'); break; case 'sha1': $t = pack('H*', '3021300906052b0e03021a05000414'); break; case 'sha256': $t = pack('H*', '3031300d060960864801650304020105000420'); break; case 'sha384': $t = pack('H*', '3041300d060960864801650304020205000430'); break; case 'sha512': $t = pack('H*', '3051300d060960864801650304020305000440'); } $t.= $h; $tLen = strlen($t); if ($emLen < $tLen + 11) { user_error('Intended encoded message length too short', E_USER_NOTICE); return false; } $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3); $em = "\0\1$ps\0$t"; return $em; } /** * RSASSA-PKCS1-V1_5-SIGN * * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}. * * @access private * @param String $m * @return String */ function _rsassa_pkcs1_v1_5_sign($m) { // EMSA-PKCS1-v1_5 encoding $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); if ($em === false) { user_error('RSA modulus too short', E_USER_NOTICE); return false; } // RSA signature $m = $this->_os2ip($em); $s = $this->_rsasp1($m); $s = $this->_i2osp($s, $this->k); // Output the signature S return $s; } /** * RSASSA-PKCS1-V1_5-VERIFY * * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}. * * @access private * @param String $m * @return String */ function _rsassa_pkcs1_v1_5_verify($m, $s) { // Length checking if (strlen($s) != $this->k) { user_error('Invalid signature', E_USER_NOTICE); return false; } // RSA verification $s = $this->_os2ip($s); $m2 = $this->_rsavp1($s); if ($m2 === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } $em = $this->_i2osp($m2, $this->k); if ($em === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } // EMSA-PKCS1-v1_5 encoding $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); if ($em2 === false) { user_error('RSA modulus too short', E_USER_NOTICE); return false; } // Compare return $em === $em2; } /** * Set Encryption Mode * * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1. * * @access public * @param Integer $mode */ function setEncryptionMode($mode) { $this->encryptionMode = $mode; } /** * Set Signature Mode * * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1 * * @access public * @param Integer $mode */ function setSignatureMode($mode) { $this->signatureMode = $mode; } /** * Encryption * * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be. * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will * be concatenated together. * * @see decrypt() * @access public * @param String $plaintext * @return String */ function encrypt($plaintext) { switch ($this->encryptionMode) { case CRYPT_RSA_ENCRYPTION_PKCS1: $length = $this->k - 11; if ($length <= 0) { return false; } $plaintext = str_split($plaintext, $length); $ciphertext = ''; foreach ($plaintext as $m) { $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m); } return $ciphertext; //case CRYPT_RSA_ENCRYPTION_OAEP: default: $length = $this->k - 2 * $this->hLen - 2; if ($length <= 0) { return false; } $plaintext = str_split($plaintext, $length); $ciphertext = ''; foreach ($plaintext as $m) { $ciphertext.= $this->_rsaes_oaep_encrypt($m); } return $ciphertext; } } /** * Decryption * * @see encrypt() * @access public * @param String $plaintext * @return String */ function decrypt($ciphertext) { if ($this->k <= 0) { return false; } $ciphertext = str_split($ciphertext, $this->k); $plaintext = ''; switch ($this->encryptionMode) { case CRYPT_RSA_ENCRYPTION_PKCS1: $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; break; //case CRYPT_RSA_ENCRYPTION_OAEP: default: $decrypt = '_rsaes_oaep_decrypt'; } foreach ($ciphertext as $c) { $temp = $this->$decrypt($c); if ($temp === false) { return false; } $plaintext.= $temp; } return $plaintext; } /** * Create a signature * * @see verify() * @access public * @param String $message * @return String */ function sign($message) { if (empty($this->modulus) || empty($this->exponent)) { return false; } switch ($this->signatureMode) { case CRYPT_RSA_SIGNATURE_PKCS1: return $this->_rsassa_pkcs1_v1_5_sign($message); //case CRYPT_RSA_SIGNATURE_PSS: default: return $this->_rsassa_pss_sign($message); } } /** * Verifies a signature * * @see sign() * @access public * @param String $message * @param String $signature * @return Boolean */ function verify($message, $signature) { if (empty($this->modulus) || empty($this->exponent)) { return false; } switch ($this->signatureMode) { case CRYPT_RSA_SIGNATURE_PKCS1: return $this->_rsassa_pkcs1_v1_5_verify($message, $signature); //case CRYPT_RSA_SIGNATURE_PSS: default: return $this->_rsassa_pss_verify($message, $signature); } } }debian/db-update/v20111210/Crypt/Random.php0000644000000000000000000001116512267045571015157 0ustar * * * * LICENSE: This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * @category Crypt * @package Crypt_Random * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt * @version $Id: Random.php,v 1.9 2010/04/24 06:40:48 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ /** * Generate a random value. * * On 32-bit machines, the largest distance that can exist between $min and $max is 2**31. * If $min and $max are farther apart than that then the last ($max - range) numbers. * * Depending on how this is being used, it may be worth while to write a replacement. For example, * a PHP-based web app that stores its data in an SQL database can collect more entropy than this function * can. * * @param optional Integer $min * @param optional Integer $max * @return Integer * @access public */ function crypt_random($min = 0, $max = 0x7FFFFFFF) { if ($min == $max) { return $min; } // see http://en.wikipedia.org/wiki//dev/random // if open_basedir is enabled file_exists() will ouput an "open_basedir restriction in effect" warning, // so we suppress it. if (@file_exists('/dev/urandom')) { static $fp; if (!$fp) { $fp = fopen('/dev/urandom', 'rb'); } extract(unpack('Nrandom', fread($fp, 4))); // say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this: // -4 % 3 + 0 = -1, even though -1 < $min return abs($random) % ($max - $min) + $min; } /* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called. Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here: http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/ The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro: http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3_2/ext/standard/php_rand.h?view=markup */ if (version_compare(PHP_VERSION, '5.2.5', '<=')) { static $seeded; if (!isset($seeded)) { $seeded = true; mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF)); } } static $crypto; // The CSPRNG's Yarrow and Fortuna periodically reseed. This function can be reseeded by hitting F5 // in the browser and reloading the page. if (!isset($crypto)) { $key = $iv = ''; for ($i = 0; $i < 8; $i++) { $key.= pack('n', mt_rand(0, 0xFFFF)); $iv .= pack('n', mt_rand(0, 0xFFFF)); } switch (true) { case class_exists('Crypt_AES'): $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); break; case class_exists('Crypt_TripleDES'): $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); break; case class_exists('Crypt_DES'): $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); break; case class_exists('Crypt_RC4'): $crypto = new Crypt_RC4(); break; default: extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF))))); return abs($random) % ($max - $min) + $min; } $crypto->setKey($key); $crypto->setIV($iv); $crypto->enableContinuousBuffer(); } extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0"))); return abs($random) % ($max - $min) + $min; } ?>debian/db-update/v20111210.sh0000755000000000000000000000011012267045571012450 0ustar #!/bin/sh cd /usr/share/spotweb/db-update/v20111210 php upgrade-db.php debian/dbsettings.inc.php0000644000000000000000000000046112267045571012627 0ustar ' + _d.title.replace('\'', '\\\'') + '