summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPreston Cody <codeman@gentoo.org>2008-02-16 21:54:40 +0000
committerPreston Cody <codeman@gentoo.org>2008-02-16 21:54:40 +0000
commita58838ed7c67c0a8216954533cf76e3118d1134e (patch)
treef2cd775a597ed8f07d92f94b63ff8f31abcb92b1
parentswitching location for config.php (diff)
downloadscire-a58838ed7c67c0a8216954533cf76e3118d1134e.tar.gz
scire-a58838ed7c67c0a8216954533cf76e3118d1134e.tar.bz2
scire-a58838ed7c67c0a8216954533cf76e3118d1134e.zip
adding in the minimal phpgacl code. this is all that is necessary
for a functioning phpgcal setup. (pretty sweet eh?) minor touchup to user.php adding favicon.ico b/c apache seems to want it. svn path=/trunk/; revision=355
-rw-r--r--scire/favicon.icobin0 -> 894 bytes
-rw-r--r--scire/phpgacl/Cache_Lite/Hashed_Cache_Lite.php184
-rw-r--r--scire/phpgacl/Cache_Lite/LICENSE458
-rw-r--r--scire/phpgacl/Cache_Lite/Lite.php615
-rw-r--r--scire/phpgacl/gacl.class.php629
-rw-r--r--scire/phpgacl/gacl_api.class.php3899
-rwxr-xr-xscire/user.php16
7 files changed, 5795 insertions, 6 deletions
diff --git a/scire/favicon.ico b/scire/favicon.ico
new file mode 100644
index 0000000..0d01a39
--- /dev/null
+++ b/scire/favicon.ico
Binary files differ
diff --git a/scire/phpgacl/Cache_Lite/Hashed_Cache_Lite.php b/scire/phpgacl/Cache_Lite/Hashed_Cache_Lite.php
new file mode 100644
index 0000000..894952f
--- /dev/null
+++ b/scire/phpgacl/Cache_Lite/Hashed_Cache_Lite.php
@@ -0,0 +1,184 @@
+<?php
+/*
+ * phpGACL - Generic Access Control List - Hashed Directory Caching.
+ * Copyright (C) 2002 Mike Benoit
+ *
+ * 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
+ *
+ * For questions, help, comments, discussion, etc., please join the
+ * phpGACL mailing list. http://sourceforge.net/mail/?group_id=57103
+ *
+ * You may contact the author of phpGACL by e-mail at:
+ * ipso@snappymail.ca
+ *
+ * The latest version of phpGACL can be obtained from:
+ * http://phpgacl.sourceforge.net/
+ *
+ */
+
+if ( !class_exists('Cache_Lite') ) {
+ require_once(dirname(__FILE__) .'/Lite.php');
+}
+
+define('DIR_SEP',DIRECTORY_SEPARATOR);
+
+class Hashed_Cache_Lite extends Cache_Lite
+{
+ /**
+ * Make a file name (with path)
+ *
+ * @param string $id cache id
+ * @param string $group name of the group
+ * @access private
+ */
+ function _setFileName($id, $group)
+ {
+ // CRC32 with SUBSTR is still faster then MD5.
+ $encoded_id = substr(crc32($id),1);
+ // $encoded_id = md5($id);
+
+ // Generate just the directory, so it can be created.
+ // Groups will have their own top level directory, for quick/easy purging of an entire group.
+ $dir = $this->_cacheDir.$group.'/'.substr($encoded_id,0,3);
+ $this->_create_dir_structure($dir);
+
+ $this->_file = $dir.'/'.$encoded_id;
+ }
+
+ /**
+ * Create full directory structure, Ripped straight from the Smarty Template engine.
+ * Version: 2.3.0
+ * Copyright: 2001,2002 ispi of Lincoln, Inc.
+ *
+ * @param string $dir Full directory.
+ * @access private
+ */
+ function _create_dir_structure($dir)
+ {
+ if (!@file_exists($dir)) {
+ $dir_parts = preg_split('![\/]+!', $dir, -1, PREG_SPLIT_NO_EMPTY);
+ $new_dir = ($dir{0} == DIR_SEP) ? DIR_SEP : '';
+ foreach ($dir_parts as $dir_part) {
+ $new_dir .= $dir_part;
+ if (!file_exists($new_dir) && !mkdir($new_dir, 0771)) {
+ Cache_Lite::raiseError('Cache_Lite : problem creating directory \"$dir\" !', -3);
+ return false;
+ }
+ $new_dir .= DIR_SEP;
+ }
+ }
+ }
+
+ function _remove_dir_structure($dir,$remove_dir = false)
+ {
+ if (in_array(substr($dir,-1),array(DIR_SEP,'/','\\'))) {
+ $dir = substr($dir,0,-1);
+ }
+
+ if (!($dh = opendir($dir))) {
+ $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
+ return false;
+ }
+
+ while ($file = readdir($dh)) {
+ if ($file == '.' || $file == '..') {
+ continue;
+ }
+ $file = $dir . DIR_SEP . $file;
+ if (is_dir($file)) {
+ $this->_remove_dir_structure($file,true);
+ continue;
+ }
+ if (is_file($file)) {
+ if (!@unlink($file)) {
+ closedir($dh);
+ $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
+ return false;
+ }
+ continue;
+ }
+ }
+
+ closedir($dh);
+
+ if ($remove_dir) {
+ clearstatcache();
+ if (!@rmdir($dir)) {
+ $this->raiseError('Cache_Lite : Unable to remove cache directory !', -4);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Clean the cache
+ *
+ * if no group is specified all cache files will be destroyed
+ * else only cache files of the specified group will be destroyed
+ *
+ * @param string $group name of the cache group
+ * @return boolean true if no problem
+ * @access public
+ */
+ function clean($group = false)
+ {
+ if ($group) {
+ $motif = $this->_cacheDir.$group.'/';
+
+ if ($this->_memoryCaching) {
+ foreach ($this->_memoryCachingArray as $key => $value) {
+ if (strpos($key, $motif, 0)) {
+ unset($this->_memoryCachingArray[$key]);
+ }
+ }
+ $this->_memoryCachingCounter = count($this->_memoryCachingArray);
+ if ($this->_onlyMemoryCaching) {
+ return true;
+ }
+ }
+
+ return $this->_remove_dir_structure($motif);
+ }
+
+ if ($this->_memoryCaching) {
+ $this->_memoryCachingArray = array();
+ $this->_memoryCachingCounter = 0;
+ if ($this->_onlyMemoryCaching) {
+ return true;
+ }
+ }
+
+ if (!($dh = opendir($this->_cacheDir))) {
+ $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
+ return false;
+ }
+
+ while ($file = readdir($dh)) {
+ if ($file == '.' || $file == '..') {
+ continue;
+ }
+ $file = $this->_cacheDir . $file;
+ if (is_dir($file) && !$this->_remove_dir_structure($file,true)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+// end of script
diff --git a/scire/phpgacl/Cache_Lite/LICENSE b/scire/phpgacl/Cache_Lite/LICENSE
new file mode 100644
index 0000000..27950e8
--- /dev/null
+++ b/scire/phpgacl/Cache_Lite/LICENSE
@@ -0,0 +1,458 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/scire/phpgacl/Cache_Lite/Lite.php b/scire/phpgacl/Cache_Lite/Lite.php
new file mode 100644
index 0000000..3341fb1
--- /dev/null
+++ b/scire/phpgacl/Cache_Lite/Lite.php
@@ -0,0 +1,615 @@
+<?php
+
+/**
+* Fast, light and safe Cache Class
+*
+* Cache_Lite is a fast, light and safe cache system. It's optimized
+* for file containers. It is fast and safe (because it uses file
+* locking and/or anti-corruption tests).
+*
+* There are some examples in the 'docs/examples' file
+* Technical choices are described in the 'docs/technical' file
+*
+* A tutorial is available in english at this url :
+* http://www.pearfr.org/index.php/en/article/cache_lite
+* (big thanks to Pierre-Alain Joye for the translation)
+*
+* The same tutorial is also available in french at this url :
+* http://www.pearfr.org/index.php/fr/article/cache_lite
+*
+* Memory Caching is from an original idea of
+* Mike BENOIT <ipso@snappymail.ca>
+*
+* @package Cache_Lite
+* @category Caching
+* @version $Id: Lite.php,v 1.1 2004/11/08 00:47:05 ipso Exp $
+* @author Fabien MARTY <fab@php.net>
+*/
+
+define('CACHE_LITE_ERROR_RETURN', 1);
+define('CACHE_LITE_ERROR_DIE', 8);
+
+class Cache_Lite
+{
+
+ // --- Private properties ---
+
+ /**
+ * Directory where to put the cache files
+ * (make sure to add a trailing slash)
+ *
+ * @var string $_cacheDir
+ */
+ var $_cacheDir = '/tmp/';
+
+ /**
+ * Enable / disable caching
+ *
+ * (can be very usefull for the debug of cached scripts)
+ *
+ * @var boolean $_caching
+ */
+ var $_caching = true;
+
+ /**
+ * Cache lifetime (in seconds)
+ *
+ * @var int $_lifeTime
+ */
+ var $_lifeTime = 3600;
+
+ /**
+ * Enable / disable fileLocking
+ *
+ * (can avoid cache corruption under bad circumstances)
+ *
+ * @var boolean $_fileLocking
+ */
+ var $_fileLocking = true;
+
+ /**
+ * Timestamp of the last valid cache
+ *
+ * @var int $_refreshTime
+ */
+ var $_refreshTime;
+
+ /**
+ * File name (with path)
+ *
+ * @var string $_file
+ */
+ var $_file;
+
+ /**
+ * Enable / disable write control (the cache is read just after writing to detect corrupt entries)
+ *
+ * Enable write control will lightly slow the cache writing but not the cache reading
+ * Write control can detect some corrupt cache files but maybe it's not a perfect control
+ *
+ * @var boolean $_writeControl
+ */
+ var $_writeControl = true;
+
+ /**
+ * Enable / disable read control
+ *
+ * If enabled, a control key is embeded in cache file and this key is compared with the one
+ * calculated after the reading.
+ *
+ * @var boolean $_writeControl
+ */
+ var $_readControl = true;
+
+ /**
+ * Type of read control (only if read control is enabled)
+ *
+ * Available values are :
+ * 'md5' for a md5 hash control (best but slowest)
+ * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
+ * 'strlen' for a length only test (fastest)
+ *
+ * @var boolean $_readControlType
+ */
+ var $_readControlType = 'crc32';
+
+ /**
+ * Pear error mode (when raiseError is called)
+ *
+ * (see PEAR doc)
+ *
+ * @see setToDebug()
+ * @var int $_pearErrorMode
+ */
+ var $_pearErrorMode = CACHE_LITE_ERROR_RETURN;
+
+ /**
+ * Current cache id
+ *
+ * @var string $_id
+ */
+ var $_id;
+
+ /**
+ * Current cache group
+ *
+ * @var string $_group
+ */
+ var $_group;
+
+ /**
+ * Enable / Disable "Memory Caching"
+ *
+ * NB : There is no lifetime for memory caching !
+ *
+ * @var boolean $_memoryCaching
+ */
+ var $_memoryCaching = false;
+
+ /**
+ * Enable / Disable "Only Memory Caching"
+ * (be carefull, memory caching is "beta quality")
+ *
+ * @var boolean $_onlyMemoryCaching
+ */
+ var $_onlyMemoryCaching = false;
+
+ /**
+ * Memory caching array
+ *
+ * @var array $_memoryCachingArray
+ */
+ var $_memoryCachingArray = array();
+
+ /**
+ * Memory caching counter
+ *
+ * @var int $memoryCachingCounter
+ */
+ var $_memoryCachingCounter = 0;
+
+ /**
+ * Memory caching limit
+ *
+ * @var int $memoryCachingLimit
+ */
+ var $_memoryCachingLimit = 1000;
+
+ /**
+ * File Name protection
+ *
+ * if set to true, you can use any cache id or group name
+ * if set to false, it can be faster but cache ids and group names
+ * will be used directly in cache file names so be carefull with
+ * special characters...
+ *
+ * @var boolean $fileNameProtection
+ */
+ var $_fileNameProtection = true;
+
+ /**
+ * Enable / disable automatic serialization
+ *
+ * it can be used to save directly datas which aren't strings
+ * (but it's slower)
+ *
+ * @var boolean $_serialize
+ */
+ var $_automaticSerialization = false;
+
+ // --- Public methods ---
+
+ /**
+ * Constructor
+ *
+ * $options is an assoc. Available options are :
+ * $options = array(
+ * 'cacheDir' => directory where to put the cache files (string),
+ * 'caching' => enable / disable caching (boolean),
+ * 'lifeTime' => cache lifetime in seconds (int),
+ * 'fileLocking' => enable / disable fileLocking (boolean),
+ * 'writeControl' => enable / disable write control (boolean),
+ * 'readControl' => enable / disable read control (boolean),
+ * 'readControlType' => type of read control 'crc32', 'md5', 'strlen' (string),
+ * 'pearErrorMode' => pear error mode (when raiseError is called) (cf PEAR doc) (int),
+ * 'memoryCaching' => enable / disable memory caching (boolean),
+ * 'onlyMemoryCaching' => enable / disable only memory caching (boolean),
+ * 'memoryCachingLimit' => max nbr of records to store into memory caching (int),
+ * 'fileNameProtection' => enable / disable automatic file name protection (boolean),
+ * 'automaticSerialization' => enable / disable automatic serialization (boolean)
+ * );
+ *
+ * @param array $options options
+ * @access public
+ */
+ function Cache_Lite($options = array(NULL))
+ {
+ $availableOptions = array('automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode');
+ foreach($options as $key => $value) {
+ if(in_array($key, $availableOptions)) {
+ $property = '_'.$key;
+ $this->$property = $value;
+ }
+ }
+ $this->_refreshTime = time() - $this->_lifeTime;
+ }
+
+ /**
+ * Test if a cache is available and (if yes) return it
+ *
+ * @param string $id cache id
+ * @param string $group name of the cache group
+ * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
+ * @return string data of the cache (or false if no cache available)
+ * @access public
+ */
+ function get($id, $group = 'default', $doNotTestCacheValidity = false)
+ {
+ $this->_id = $id;
+ $this->_group = $group;
+ $data = false;
+ if ($this->_caching) {
+ $this->_setFileName($id, $group);
+ if ($this->_memoryCaching) {
+ if (isset($this->_memoryCachingArray[$this->_file])) {
+ if ($this->_automaticSerialization) {
+ return unserialize($this->_memoryCachingArray[$this->_file]);
+ } else {
+ return $this->_memoryCachingArray[$this->_file];
+ }
+ } else {
+ if ($this->_onlyMemoryCaching) {
+ return false;
+ }
+ }
+ }
+ if ($doNotTestCacheValidity) {
+ if (file_exists($this->_file)) {
+ $data = $this->_read();
+ }
+ } else {
+ if ((file_exists($this->_file)) && (@filemtime($this->_file) > $this->_refreshTime)) {
+ $data = $this->_read();
+ }
+ }
+ if (($data) and ($this->_memoryCaching)) {
+ $this->_memoryCacheAdd($this->_file, $data);
+ }
+ if (($this->_automaticSerialization) and (is_string($data))) {
+ $data = unserialize($data);
+ }
+ return $data;
+ }
+ return false;
+ }
+
+ /**
+ * Save some data in a cache file
+ *
+ * @param string $data data to put in cache (can be another type than strings if automaticSerialization is on)
+ * @param string $id cache id
+ * @param string $group name of the cache group
+ * @return boolean true if no problem
+ * @access public
+ */
+ function save($data, $id = NULL, $group = 'default')
+ {
+ if ($this->_caching) {
+ if ($this->_automaticSerialization) {
+ $data = serialize($data);
+ }
+ if (isset($id)) {
+ $this->_setFileName($id, $group);
+ }
+ if ($this->_memoryCaching) {
+ $this->_memoryCacheAdd($this->_file, $data);
+ if ($this->_onlyMemoryCaching) {
+ return true;
+ }
+ }
+ if ($this->_writeControl) {
+ if (!$this->_writeAndControl($data)) {
+ @touch($this->_file, time() - 2*abs($this->_lifeTime));
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return $this->_write($data);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Remove a cache file
+ *
+ * @param string $id cache id
+ * @param string $group name of the cache group
+ * @return boolean true if no problem
+ * @access public
+ */
+ function remove($id, $group = 'default')
+ {
+ $this->_setFileName($id, $group);
+ if ($this->_memoryCaching) {
+ if (isset($this->_memoryCachingArray[$this->_file])) {
+ unset($this->_memoryCachingArray[$this->_file]);
+ $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
+ }
+ if ($this->_onlyMemoryCaching) {
+ return true;
+ }
+ }
+ if (!@unlink($this->_file)) {
+ $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Clean the cache
+ *
+ * if no group is specified all cache files will be destroyed
+ * else only cache files of the specified group will be destroyed
+ *
+ * @param string $group name of the cache group
+ * @return boolean true if no problem
+ * @access public
+ */
+ function clean($group = false)
+ {
+ if ($this->_fileNameProtection) {
+ $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_';
+ } else {
+ $motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
+ }
+ if ($this->_memoryCaching) {
+ while (list($key, $value) = each($this->_memoryCachingArray)) {
+ if (strpos($key, $motif, 0)) {
+ unset($this->_memoryCachingArray[$key]);
+ $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
+ }
+ }
+ if ($this->_onlyMemoryCaching) {
+ return true;
+ }
+ }
+ if (!($dh = opendir($this->_cacheDir))) {
+ $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
+ return false;
+ }
+ while ($file = readdir($dh)) {
+ if (($file != '.') && ($file != '..')) {
+ $file = $this->_cacheDir . $file;
+ if (is_file($file)) {
+ if (strpos($file, $motif, 0)) {
+ if (!@unlink($file)) {
+ $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Set to debug mode
+ *
+ * When an error is found, the script will stop and the message will be displayed
+ * (in debug mode only).
+ *
+ * @access public
+ */
+ function setToDebug()
+ {
+ $this->_pearErrorMode = CACHE_LITE_ERROR_DIE;
+ }
+
+ /**
+ * Set a new life time
+ *
+ * @param int $newLifeTime new life time (in seconds)
+ * @access public
+ */
+ function setLifeTime($newLifeTime)
+ {
+ $this->_lifeTime = $newLifeTime;
+ $this->_refreshTime = time() - $newLifeTime;
+ }
+
+ /**
+ *
+ * @access public
+ */
+ function saveMemoryCachingState($id, $group = 'default')
+ {
+ if ($this->_caching) {
+ $array = array(
+ 'counter' => $this->_memoryCachingCounter,
+ 'array' => $this->_memoryCachingState
+ );
+ $data = serialize($array);
+ $this->save($data, $id, $group);
+ }
+ }
+
+ /**
+ *
+ * @access public
+ */
+ function getMemoryCachingState($id, $group = 'default', $doNotTestCacheValidity = false)
+ {
+ if ($this->_caching) {
+ if ($data = $this->get($id, $group, $doNotTestCacheValidity)) {
+ $array = unserialize($data);
+ $this->_memoryCachingCounter = $array['counter'];
+ $this->_memoryCachingArray = $array['array'];
+ }
+ }
+ }
+
+ /**
+ * Return the cache last modification time
+ *
+ * BE CAREFUL : THIS METHOD IS FOR HACKING ONLY !
+ *
+ * @return int last modification time
+ */
+ function lastModified() {
+ return filemtime($this->_file);
+ }
+
+ /**
+ * Trigger a PEAR error
+ *
+ * To improve performances, the PEAR.php file is included dynamically.
+ * The file is so included only when an error is triggered. So, in most
+ * cases, the file isn't included and perfs are much better.
+ *
+ * @param string $msg error message
+ * @param int $code error code
+ * @access public
+ */
+ function raiseError($msg, $code)
+ {
+ include_once('PEAR.php');
+ PEAR::raiseError($msg, $code, $this->_pearErrorMode);
+ }
+
+ // --- Private methods ---
+
+ /**
+ *
+ * @access private
+ */
+ function _memoryCacheAdd($id, $data)
+ {
+ $this->_memoryCachingArray[$this->_file] = $data;
+ if ($this->_memoryCachingCounter >= $this->_memoryCachingLimit) {
+ list($key, $value) = each($this->_memoryCachingArray);
+ unset($this->_memoryCachingArray[$key]);
+ } else {
+ $this->_memoryCachingCounter = $this->_memoryCachingCounter + 1;
+ }
+ }
+
+ /**
+ * Make a file name (with path)
+ *
+ * @param string $id cache id
+ * @param string $group name of the group
+ * @access private
+ */
+ function _setFileName($id, $group)
+ {
+ if ($this->_fileNameProtection) {
+ $this->_file = ($this->_cacheDir.'cache_'.md5($group).'_'.md5($id));
+ } else {
+ $this->_file = $this->_cacheDir.'cache_'.$group.'_'.$id;
+ }
+ }
+
+ /**
+ * Read the cache file and return the content
+ *
+ * @return string content of the cache file
+ * @access private
+ */
+ function _read()
+ {
+ $fp = @fopen($this->_file, "rb");
+ if ($this->_fileLocking) @flock($fp, LOCK_SH);
+ if ($fp) {
+ clearstatcache(); // because the filesize can be cached by PHP itself...
+ $length = @filesize($this->_file);
+ $mqr = get_magic_quotes_runtime();
+ set_magic_quotes_runtime(0);
+ if ($this->_readControl) {
+ $hashControl = @fread($fp, 32);
+ $length = $length - 32;
+ }
+ $data = @fread($fp, $length);
+ set_magic_quotes_runtime($mqr);
+ if ($this->_fileLocking) @flock($fp, LOCK_UN);
+ @fclose($fp);
+ if ($this->_readControl) {
+ $hashData = $this->_hash($data, $this->_readControlType);
+ if ($hashData != $hashControl) {
+ @touch($this->_file, time() - 2*abs($this->_lifeTime));
+ return false;
+ }
+ }
+ return $data;
+ }
+ $this->raiseError('Cache_Lite : Unable to read cache !', -2);
+ return false;
+ }
+
+ /**
+ * Write the given data in the cache file
+ *
+ * @param string $data data to put in cache
+ * @return boolean true if ok
+ * @access private
+ */
+ function _write($data)
+ {
+ $fp = @fopen($this->_file, "wb");
+ if ($fp) {
+ if ($this->_fileLocking) @flock($fp, LOCK_EX);
+ if ($this->_readControl) {
+ @fwrite($fp, $this->_hash($data, $this->_readControlType), 32);
+ }
+ $len = strlen($data);
+ @fwrite($fp, $data, $len);
+ if ($this->_fileLocking) @flock($fp, LOCK_UN);
+ @fclose($fp);
+ return true;
+ }
+ $this->raiseError('Cache_Lite : Unable to write cache !', -1);
+ return false;
+ }
+
+ /**
+ * Write the given data in the cache file and control it just after to avoir corrupted cache entries
+ *
+ * @param string $data data to put in cache
+ * @return boolean true if the test is ok
+ * @access private
+ */
+ function _writeAndControl($data)
+ {
+ $this->_write($data);
+ $dataRead = $this->_read($data);
+ return ($dataRead==$data);
+ }
+
+ /**
+ * Make a control key with the string containing datas
+ *
+ * @param string $data data
+ * @param string $controlType type of control 'md5', 'crc32' or 'strlen'
+ * @return string control key
+ * @access private
+ */
+ function _hash($data, $controlType)
+ {
+ switch ($controlType) {
+ case 'md5':
+ return md5($data);
+ case 'crc32':
+ return sprintf('% 32d', crc32($data));
+ case 'strlen':
+ return sprintf('% 32d', strlen($data));
+ default:
+ $this->raiseError('Unknown controlType ! (available values are only \'md5\', \'crc32\', \'strlen\')', -5);
+ }
+ }
+
+}
+
+?>
diff --git a/scire/phpgacl/gacl.class.php b/scire/phpgacl/gacl.class.php
new file mode 100644
index 0000000..b8832a1
--- /dev/null
+++ b/scire/phpgacl/gacl.class.php
@@ -0,0 +1,629 @@
+<?php
+// $Id: gacl.class.php,v 1.53 2005/10/13 19:53:08 ipso Exp $
+
+/**
+ * phpGACL - Generic Access Control List
+ * Copyright (C) 2002,2003 Mike Benoit
+ *
+ * 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
+ *
+ * For questions, help, comments, discussion, etc., please join the
+ * phpGACL mailing list. http://sourceforge.net/mail/?group_id=57103
+ *
+ * You may contact the author of phpGACL by e-mail at:
+ * ipso@snappymail.ca
+ *
+ * The latest version of phpGACL can be obtained from:
+ * http://phpgacl.sourceforge.net/
+ *
+ * @package phpGACL
+ */
+
+/*
+ * Path to ADODB.
+ */
+if ( !defined('ADODB_DIR') ) {
+ define('ADODB_DIR', $ADOdb_path);
+}
+
+/**
+* phpGACL main class
+*
+* Class gacl should be used in applications where only querying the phpGACL
+* database is required.
+*
+* @package phpGACL
+* @author Mike Benoit <ipso@snappymail.ca>
+*/
+class gacl {
+ /*
+ --- phpGACL Configuration path/file ---
+ */
+ var $config_file = './gacl.ini.php';
+
+ /*
+ --- Private properties ---
+ */
+ /** @var boolean Enables Debug output if true */
+ var $_debug = FALSE;
+# var $_debug = True;
+ /*
+ --- Database configuration. ---
+ */
+ /** @var string Prefix for all the phpgacl tables in the database */
+ var $_db_table_prefix = 'gacl_';
+
+ /** @var string The database type, based on available ADODB connectors - mysql, postgres7, sybase, oci8po See here for more: http://php.weblogs.com/adodb_manual#driverguide */
+ var $_db_type = '';
+
+ /** @var string The database server */
+ var $_db_host = '';
+
+ /** @var string The database user name */
+ var $_db_user = '';
+
+ /** @var string The database user password */
+ var $_db_password = '';
+
+ /** @var string The database name */
+ var $_db_name = '';
+
+ /** @var object An ADODB database connector object */
+ var $_db = '';
+
+ /*
+ * NOTE: This cache must be manually cleaned each time ACL's are modified.
+ * Alternatively you could wait for the cache to expire.
+ */
+
+ /** @var boolean Caches queries if true */
+ var $_caching = FALSE;
+
+ /** @var boolean Force cache to expire */
+ var $_force_cache_expire = TRUE;
+
+ /** @var string The directory for cache file to eb written (ensure write permission are set) */
+ var $_cache_dir = '/tmp/phpgacl_cache'; // NO trailing slash
+
+ /** @var int The time for the cache to expire in seconds - 600 == Ten Minutes */
+ var $_cache_expire_time=600;
+
+ /** @var string A switch to put acl_check into '_group_' mode */
+ var $_group_switch = '_group_';
+
+ /**
+ * Constructor
+ * @param array An arry of options to oeverride the class defaults
+ */
+ function gacl($options = NULL) {
+
+ $available_options = array('db','debug','items_per_page','max_select_box_items','max_search_return_items','db_table_prefix','db_type','db_host','db_user','db_password','db_name','caching','force_cache_expire','cache_dir','cache_expire_time');
+
+ //Values supplied in $options array overwrite those in the config file.
+ if ( file_exists($this->config_file) ) {
+ $config = parse_ini_file($this->config_file);
+
+ if ( is_array($config) ) {
+ $gacl_options = array_merge($config, $options);
+ }
+
+ unset($config);
+ }
+
+ if (is_array($options)) {
+ foreach ($options as $key => $value) {
+ $this->debug_text("Option: $key");
+
+ if (in_array($key, $available_options) ) {
+ $this->debug_text("Valid Config options: $key");
+ $property = '_'.$key;
+ $this->$property = $value;
+ } else {
+ $this->debug_text("ERROR: Config option: $key is not a valid option");
+ }
+ }
+ }
+
+ require_once( ADODB_DIR .'/adodb.inc.php');
+ require_once( ADODB_DIR .'/adodb-pager.inc.php');
+
+ //Use NUM for slight performance/memory reasons.
+ //Leave this in for backwards compatibility with older ADODB installations.
+ //If your using ADODB v3.5+ feel free to comment out the following line if its giving you problems.
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ if (is_object($this->_db)) {
+ $this->db = &$this->_db;
+ } else {
+ $this->db = ADONewConnection($this->_db_type);
+ $this->db->SetFetchMode(ADODB_FETCH_NUM);
+ $this->db->PConnect($this->_db_host, $this->_db_user, $this->_db_password, $this->_db_name);
+ }
+ $this->db->debug = $this->_debug;
+
+ if ( $this->_caching == TRUE ) {
+ if (!class_exists('Hashed_Cache_Lite')) {
+ require_once(dirname(__FILE__) .'/Cache_Lite/Hashed_Cache_Lite.php');
+ }
+
+ /*
+ * Cache options. We default to the highest performance. If you run in to cache corruption problems,
+ * Change all the 'false' to 'true', this will slow things down slightly however.
+ */
+
+ $cache_options = array(
+ 'caching' => $this->_caching,
+ 'cacheDir' => $this->_cache_dir.'/',
+ 'lifeTime' => $this->_cache_expire_time,
+ 'fileLocking' => TRUE,
+ 'writeControl' => FALSE,
+ 'readControl' => FALSE,
+ 'memoryCaching' => TRUE,
+ 'automaticSerialization' => FALSE
+ );
+ $this->Cache_Lite = new Hashed_Cache_Lite($cache_options);
+ }
+
+ return true;
+ }
+
+ /**
+ * Prints debug text if debug is enabled.
+ * @param string THe text to output
+ * @return boolean Always returns true
+ */
+ function debug_text($text) {
+
+ if ($this->_debug) {
+ echo "$text<br>\n";
+ }
+
+ return true;
+ }
+
+ /**
+ * Prints database debug text if debug is enabled.
+ * @param string The name of the function calling this method
+ * @return string Returns an error message
+ */
+ function debug_db($function_name = '') {
+ if ($function_name != '') {
+ $function_name .= ' (): ';
+ }
+
+ return $this->debug_text ($function_name .'database error: '. $this->db->ErrorMsg() .' ('. $this->db->ErrorNo() .')');
+ }
+
+ /**
+ * Wraps the actual acl_query() function.
+ *
+ * It is simply here to return TRUE/FALSE accordingly.
+ * @param string The ACO section value
+ * @param string The ACO value
+ * @param string The ARO section value
+ * @param string The ARO section
+ * @param string The AXO section value (optional)
+ * @param string The AXO section value (optional)
+ * @param integer The group id of the ARO ??Mike?? (optional)
+ * @param integer The group id of the AXO ??Mike?? (optional)
+ * @return boolean TRUE if the check succeeds, false if not.
+ */
+ function acl_check($aco_section_value, $aco_value, $aro_section_value, $aro_value, $axo_section_value=NULL, $axo_value=NULL, $root_aro_group=NULL, $root_axo_group=NULL) {
+ $acl_result = $this->acl_query($aco_section_value, $aco_value, $aro_section_value, $aro_value, $axo_section_value, $axo_value, $root_aro_group, $root_axo_group);
+
+ return $acl_result['allow'];
+ }
+
+ /**
+ * Wraps the actual acl_query() function.
+ *
+ * Quick access to the return value of an ACL.
+ * @param string The ACO section value
+ * @param string The ACO value
+ * @param string The ARO section value
+ * @param string The ARO section
+ * @param string The AXO section value (optional)
+ * @param string The AXO section value (optional)
+ * @param integer The group id of the ARO (optional)
+ * @param integer The group id of the AXO (optional)
+ * @return string The return value of the ACL
+ */
+ function acl_return_value($aco_section_value, $aco_value, $aro_section_value, $aro_value, $axo_section_value=NULL, $axo_value=NULL, $root_aro_group=NULL, $root_axo_group=NULL) {
+ $acl_result = $this->acl_query($aco_section_value, $aco_value, $aro_section_value, $aro_value, $axo_section_value, $axo_value, $root_aro_group, $root_axo_group);
+
+ return $acl_result['return_value'];
+ }
+
+ /**
+ * Handles ACL lookups over arrays of AROs
+ * @param string The ACO section value
+ * @param string The ACO value
+ * @param array An named array of arrays, each element in the format aro_section_value=>array(aro_value1,aro_value1,...)
+ * @return mixed The same data format as inputted.
+ \*======================================================================*/
+ function acl_check_array($aco_section_value, $aco_value, $aro_array) {
+ /*
+ Input Array:
+ Section => array(Value, Value, Value),
+ Section => array(Value, Value, Value)
+
+ */
+
+ if (!is_array($aro_array)) {
+ $this->debug_text("acl_query_array(): ARO Array must be passed");
+ return false;
+ }
+
+ foreach($aro_array as $aro_section_value => $aro_value_array) {
+ foreach ($aro_value_array as $aro_value) {
+ $this->debug_text("acl_query_array(): ARO Section Value: $aro_section_value ARO VALUE: $aro_value");
+
+ if( $this->acl_check($aco_section_value, $aco_value, $aro_section_value, $aro_value) ) {
+ $this->debug_text("acl_query_array(): ACL_CHECK True");
+ $retarr[$aro_section_value][] = $aro_value;
+ } else {
+ $this->debug_text("acl_query_array(): ACL_CHECK False");
+ }
+ }
+ }
+
+ return $retarr;
+
+ }
+
+ /**
+ * The Main function that does the actual ACL lookup.
+ * @param string The ACO section value
+ * @param string The ACO value
+ * @param string The ARO section value
+ * @param string The ARO section
+ * @param string The AXO section value (optional)
+ * @param string The AXO section value (optional)
+ * @param string The value of the ARO group (optional)
+ * @param string The value of the AXO group (optional)
+ * @param boolean Debug the operation if true (optional)
+ * @return array Returns as much information as possible about the ACL so other functions can trim it down and omit unwanted data.
+ */
+ function acl_query($aco_section_value, $aco_value, $aro_section_value, $aro_value, $axo_section_value=NULL, $axo_value=NULL, $root_aro_group=NULL, $root_axo_group=NULL, $debug=NULL) {
+
+ $cache_id = 'acl_query_'.$aco_section_value.'-'.$aco_value.'-'.$aro_section_value.'-'.$aro_value.'-'.$axo_section_value.'-'.$axo_value.'-'.$root_aro_group.'-'.$root_axo_group.'-'.$debug;
+
+ $retarr = $this->get_cache($cache_id);
+
+ if (!$retarr) {
+ /*
+ * Grab all groups mapped to this ARO/AXO
+ */
+ $aro_group_ids = $this->acl_get_groups($aro_section_value, $aro_value, $root_aro_group, 'ARO');
+
+ if (is_array($aro_group_ids) AND !empty($aro_group_ids)) {
+ $sql_aro_group_ids = implode(',', $aro_group_ids);
+ }
+
+ if ($axo_section_value != '' AND $axo_value != '') {
+ $axo_group_ids = $this->acl_get_groups($axo_section_value, $axo_value, $root_axo_group, 'AXO');
+
+ if (is_array($axo_group_ids) AND !empty($axo_group_ids)) {
+ $sql_axo_group_ids = implode(',', $axo_group_ids);
+ }
+ }
+
+ /*
+ * This query is where all the magic happens.
+ * The ordering is very important here, as well very tricky to get correct.
+ * Currently there can be duplicate ACLs, or ones that step on each other toes. In this case, the ACL that was last updated/created
+ * is used.
+ *
+ * This is probably where the most optimizations can be made.
+ */
+
+ $order_by = array();
+
+ $query = '
+ SELECT a.id,a.allow,a.return_value
+ FROM '. $this->_db_table_prefix .'acl a
+ LEFT JOIN '. $this->_db_table_prefix .'aco_map ac ON ac.acl_id=a.id';
+
+ if ($aro_section_value != $this->_group_switch) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'aro_map ar ON ar.acl_id=a.id';
+ }
+
+ if ($axo_section_value != $this->_group_switch) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'axo_map ax ON ax.acl_id=a.id';
+ }
+
+ /*
+ * if there are no aro groups, don't bother doing the join.
+ */
+ if (isset($sql_aro_group_ids)) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'aro_groups_map arg ON arg.acl_id=a.id
+ LEFT JOIN '. $this->_db_table_prefix .'aro_groups rg ON rg.id=arg.group_id';
+ }
+
+ // this join is necessary to weed out rules associated with axo groups
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'axo_groups_map axg ON axg.acl_id=a.id';
+
+ /*
+ * if there are no axo groups, don't bother doing the join.
+ * it is only used to rank by the level of the group.
+ */
+ if (isset($sql_axo_group_ids)) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'axo_groups xg ON xg.id=axg.group_id';
+ }
+
+ //Move the below line to the LEFT JOIN above for PostgreSQL's sake.
+ //AND ac.acl_id=a.id
+ $query .= '
+ WHERE a.enabled=1
+ AND (ac.section_value='. $this->db->quote($aco_section_value) .' AND ac.value='. $this->db->quote($aco_value) .')';
+
+ // if we are querying an aro group
+ if ($aro_section_value == $this->_group_switch) {
+ // if acl_get_groups did not return an array
+ if ( !isset ($sql_aro_group_ids) ) {
+ $this->debug_text ('acl_query(): Invalid ARO Group: '. $aro_value);
+ return FALSE;
+ }
+
+ $query .= '
+ AND rg.id IN ('. $sql_aro_group_ids .')';
+
+ $order_by[] = '(rg.rgt-rg.lft) ASC';
+ } else {
+ $query .= '
+ AND ((ar.section_value='. $this->db->quote($aro_section_value) .' AND ar.value='. $this->db->quote($aro_value) .')';
+
+ if ( isset ($sql_aro_group_ids) ) {
+ $query .= ' OR rg.id IN ('. $sql_aro_group_ids .')';
+
+ $order_by[] = '(CASE WHEN ar.value IS NULL THEN 0 ELSE 1 END) DESC';
+ $order_by[] = '(rg.rgt-rg.lft) ASC';
+ }
+
+ $query .= ')';
+ }
+
+
+ // if we are querying an axo group
+ if ($axo_section_value == $this->_group_switch) {
+ // if acl_get_groups did not return an array
+ if ( !isset ($sql_axo_group_ids) ) {
+ $this->debug_text ('acl_query(): Invalid AXO Group: '. $axo_value);
+ return FALSE;
+ }
+
+ $query .= '
+ AND xg.id IN ('. $sql_axo_group_ids .')';
+
+ $order_by[] = '(xg.rgt-xg.lft) ASC';
+ } else {
+ $query .= '
+ AND (';
+
+ if ($axo_section_value == '' AND $axo_value == '') {
+ $query .= '(ax.section_value IS NULL AND ax.value IS NULL)';
+ } else {
+ $query .= '(ax.section_value='. $this->db->quote($axo_section_value) .' AND ax.value='. $this->db->quote($axo_value) .')';
+ }
+
+ if (isset($sql_axo_group_ids)) {
+ $query .= ' OR xg.id IN ('. $sql_axo_group_ids .')';
+
+ $order_by[] = '(CASE WHEN ax.value IS NULL THEN 0 ELSE 1 END) DESC';
+ $order_by[] = '(xg.rgt-xg.lft) ASC';
+ } else {
+ $query .= ' AND axg.group_id IS NULL';
+ }
+
+ $query .= ')';
+ }
+
+ /*
+ * The ordering is always very tricky and makes all the difference in the world.
+ * Order (ar.value IS NOT NULL) DESC should put ACLs given to specific AROs
+ * ahead of any ACLs given to groups. This works well for exceptions to groups.
+ */
+
+ $order_by[] = 'a.updated_date DESC';
+
+ $query .= '
+ ORDER BY '. implode (',', $order_by) . '
+ ';
+
+ // we are only interested in the first row
+ $rs = $this->db->SelectLimit($query, 1);
+
+ if (!is_object($rs)) {
+ $this->debug_db('acl_query');
+ return FALSE;
+ }
+
+ $row =& $rs->FetchRow();
+
+ /*
+ * Return ACL ID. This is the key to "hooking" extras like pricing assigned to ACLs etc... Very useful.
+ */
+ if (is_array($row)) {
+ // Permission granted?
+ // This below oneliner is very confusing.
+ //$allow = (isset($row[1]) AND $row[1] == 1);
+
+ //Prefer this.
+ if ( isset($row[1]) AND $row[1] == 1 ) {
+ $allow = TRUE;
+ } else {
+ $allow = FALSE;
+ }
+
+ $retarr = array('acl_id' => &$row[0], 'return_value' => &$row[2], 'allow' => $allow);
+ } else {
+ // Permission denied.
+ $retarr = array('acl_id' => NULL, 'return_value' => NULL, 'allow' => FALSE);
+ }
+
+ /*
+ * Return the query that we ran if in debug mode.
+ */
+ if ($debug == TRUE) {
+ $retarr['query'] = &$query;
+ }
+
+ //Cache data.
+ $this->put_cache($retarr, $cache_id);
+ }
+
+ $this->debug_text("<b>acl_query():</b> ACO Section: $aco_section_value ACO Value: $aco_value ARO Section: $aro_section_value ARO Value $aro_value ACL ID: ". $retarr['acl_id'] .' Result: '. $retarr['allow']);
+ return $retarr;
+ }
+
+ /**
+ * Grabs all groups mapped to an ARO. You can also specify a root_group for subtree'ing.
+ * @param string The section value or the ARO or ACO
+ * @param string The value of the ARO or ACO
+ * @param integer The group id of the group to start at (optional)
+ * @param string The type of group, either ARO or AXO (optional)
+ */
+ function acl_get_groups($section_value, $value, $root_group=NULL, $group_type='ARO') {
+
+ switch(strtolower($group_type)) {
+ case 'axo':
+ $group_type = 'axo';
+ $object_table = $this->_db_table_prefix .'axo';
+ $group_table = $this->_db_table_prefix .'axo_groups';
+ $group_map_table = $this->_db_table_prefix .'groups_axo_map';
+ break;
+ default:
+ $group_type = 'aro';
+ $object_table = $this->_db_table_prefix .'aro';
+ $group_table = $this->_db_table_prefix .'aro_groups';
+ $group_map_table = $this->_db_table_prefix .'groups_aro_map';
+ break;
+ }
+
+ //$profiler->startTimer( "acl_get_groups()");
+
+ //Generate unique cache id.
+ $cache_id = 'acl_get_groups_'.$section_value.'-'.$value.'-'.$root_group.'-'.$group_type;
+
+ $retarr = $this->get_cache($cache_id);
+
+ if (!$retarr) {
+
+ // Make sure we get the groups
+ $query = '
+ SELECT DISTINCT g2.id';
+
+ if ($section_value == $this->_group_switch) {
+ $query .= '
+ FROM ' . $group_table . ' g1,' . $group_table . ' g2';
+
+ $where = '
+ WHERE g1.value=' . $this->db->quote( $value );
+ } else {
+ $query .= '
+ FROM '. $object_table .' o,'. $group_map_table .' gm,'. $group_table .' g1,'. $group_table .' g2';
+
+ $where = '
+ WHERE (o.section_value='. $this->db->quote($section_value) .' AND o.value='. $this->db->quote($value) .')
+ AND gm.'. $group_type .'_id=o.id
+ AND g1.id=gm.group_id';
+ }
+
+ /*
+ * If root_group_id is specified, we have to narrow this query down
+ * to just groups deeper in the tree then what is specified.
+ * This essentially creates a virtual "subtree" and ignores all outside groups.
+ * Useful for sites like sourceforge where you may seperate groups by "project".
+ */
+ if ( $root_group != '') {
+ //It is important to note the below line modifies the tables being selected.
+ //This is the reason for the WHERE variable.
+ $query .= ','. $group_table .' g3';
+
+ $where .= '
+ AND g3.value='. $this->db->quote( $root_group ) .'
+ AND ((g2.lft BETWEEN g3.lft AND g1.lft) AND (g2.rgt BETWEEN g1.rgt AND g3.rgt))';
+ } else {
+ $where .= '
+ AND (g2.lft <= g1.lft AND g2.rgt >= g1.rgt)';
+ }
+
+ $query .= $where;
+
+ // $this->debug_text($query);
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('acl_get_groups');
+ return FALSE;
+ }
+
+ $retarr = array();
+
+ //Unbuffered query?
+ while (!$rs->EOF) {
+ $retarr[] = reset($rs->fields);
+ $rs->MoveNext();
+ }
+
+ //Cache data.
+ $this->put_cache($retarr, $cache_id);
+ }
+
+ return $retarr;
+ }
+
+ /**
+ * Uses PEAR's Cache_Lite package to grab cached arrays, objects, variables etc...
+ * using unserialize() so it can handle more then just text string.
+ * @param string The id of the cached object
+ * @return mixed The cached object, otherwise FALSE if the object identifier was not found
+ */
+ function get_cache($cache_id) {
+
+ if ( $this->_caching == TRUE ) {
+ $this->debug_text("get_cache(): on ID: $cache_id");
+
+ if ( is_string($this->Cache_Lite->get($cache_id) ) ) {
+ return unserialize($this->Cache_Lite->get($cache_id) );
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Uses PEAR's Cache_Lite package to write cached arrays, objects, variables etc...
+ * using serialize() so it can handle more then just text string.
+ * @param mixed A variable to cache
+ * @param string The id of the cached variable
+ */
+ function put_cache($data, $cache_id) {
+
+ if ( $this->_caching == TRUE ) {
+ $this->debug_text("put_cache(): Cache MISS on ID: $cache_id");
+
+ return $this->Cache_Lite->save(serialize($data), $cache_id);
+ }
+
+ return false;
+ }
+}
+?>
diff --git a/scire/phpgacl/gacl_api.class.php b/scire/phpgacl/gacl_api.class.php
new file mode 100644
index 0000000..70833fc
--- /dev/null
+++ b/scire/phpgacl/gacl_api.class.php
@@ -0,0 +1,3899 @@
+<?php
+/**
+ * phpGACL - Generic Access Control List
+ * Copyright (C) 2002,2003 Mike Benoit
+ *
+ * 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
+ *
+ * For questions, help, comments, discussion, etc., please join the
+ * phpGACL mailing list. http://sourceforge.net/mail/?group_id=57103
+ *
+ * You may contact the author of phpGACL by e-mail at:
+ * ipso@snappymail.ca
+ *
+ * The latest version of phpGACL can be obtained from:
+ * http://phpgacl.sourceforge.net/
+ *
+ * @package phpGACL
+ *
+ */
+
+/*
+ *
+ * For examples, see example.php or the Administration interface,
+ * as it makes use of nearly every API Call.
+ *
+ */
+/**
+ * gacl_api Extended API Class
+ *
+ * Class gacl_api should be used for applications that must interface directly with
+ * phpGACL's data structures, objects, and rules.
+ *
+ * @package phpGACL
+ * @author Mike Benoit <ipso@snappymail.ca>
+ *
+ */
+
+class gacl_api extends gacl {
+
+ /*
+ *
+ * Misc helper functions.
+ *
+ */
+
+ /**
+ * showarray()
+ *
+ * Dump all contents of an array in HTML (kinda)
+ *
+ * @param array
+ *
+ */
+ function showarray($array) {
+ echo "<br><pre>\n";
+ var_dump($array);
+ echo "</pre><br>\n";
+ }
+
+ /**
+ * count_all()
+ *
+ * Recursively counts elements in an array and sub-arrays.
+ *
+ * This is different from count($arg, COUNT_RECURSIVE)
+ * in PHP >= 4.2.0, which includes sub-arrays in the count.
+ *
+ * @return int The returned count is a count of all scalar elements found.
+ *
+ * @param array Array to count
+ */
+ function count_all($arg = NULL) {
+ switch (TRUE) {
+ case is_scalar($arg):
+ case is_object($arg):
+ // single object
+ return 1;
+ case is_array($arg):
+ // call recursively for all elements of $arg
+ $count = 0;
+ foreach ($arg as $val) {
+ $count += $this->count_all($val);
+ }
+ return $count;
+ }
+ return FALSE;
+ }
+
+ /**
+ * get_version()
+ *
+ * Grabs phpGACL version from the database.
+ *
+ * @return string Version of phpGACL
+ */
+ function get_version() {
+ $query = "select value from ".$this->_db_table_prefix."phpgacl where name = 'version'";
+ $version = $this->db->GetOne($query);
+
+ return $version;
+ }
+
+ /**
+ * get_schema_version()
+ *
+ * Grabs phpGACL schema version from the database.
+ *
+ * @return string Schema Version
+ */
+ function get_schema_version() {
+ $query = "select value from ".$this->_db_table_prefix."phpgacl where name = 'schema_version'";
+ $version = $this->db->GetOne($query);
+
+ return $version;
+ }
+
+ /*
+ *
+ * ACL
+ *
+ */
+
+ /**
+ * consolidated_edit_acl()
+ *
+ * Add's an ACL but checks to see if it can consolidate it with another one first.
+ *
+ * This ONLY works with ACO's and ARO's. Groups, and AXO are excluded.
+ * As well this function is designed for handling ACLs with return values,
+ * and consolidating on the return_value, in hopes of keeping the ACL count to a minimum.
+ *
+ * A return value of false must _always_ be handled outside this function.
+ * As this function will remove AROs from ACLs and return false, in most cases
+ * you will need to a create a completely new ACL on a false return.
+ *
+ * @return bool Special boolean return value. See note.
+ *
+ * @param string ACO Section Value
+ * @param string ACO Value
+ * @param string ARO Section Value
+ * @param string ARO Value
+ * @param string Return Value of ACL
+ */
+ function consolidated_edit_acl($aco_section_value, $aco_value, $aro_section_value, $aro_value, $return_value) {
+
+ $this->debug_text("consolidated_edit_acl(): ACO Section Value: $aco_section_value ACO Value: $aco_value ARO Section Value: $aro_section_value ARO Value: $aro_value Return Value: $return_value");
+
+ $acl_ids = array();
+
+ if (empty($aco_section_value) ) {
+ $this->debug_text("consolidated_edit_acl(): ACO Section Value ($aco_section_value) is empty, this is required!");
+ return false;
+ }
+
+ if (empty($aco_value) ) {
+ $this->debug_text("consolidated_edit_acl(): ACO Value ($aco_value) is empty, this is required!");
+ return false;
+ }
+
+ if (empty($aro_section_value) ) {
+ $this->debug_text("consolidated_edit_acl(): ARO Section Value ($aro_section_value) is empty, this is required!");
+ return false;
+ }
+
+ if (empty($aro_value) ) {
+ $this->debug_text("consolidated_edit_acl(): ARO Value ($aro_value) is empty, this is required!");
+ return false;
+ }
+
+ if (empty($return_value) ) {
+ $this->debug_text("consolidated_edit_acl(): Return Value ($return_value) is empty, this is required!");
+ return false;
+ }
+
+ //See if a current ACL exists with the current objects, excluding return value
+ $current_acl_ids = $this->search_acl($aco_section_value, $aco_value, $aro_section_value, $aro_value, FALSE, FALSE, FALSE, FALSE, FALSE);
+ //showarray($current_acl_ids);
+
+ if (is_array($current_acl_ids)) {
+ $this->debug_text("add_consolidated_acl(): Found current ACL_IDs, counting ACOs");
+
+ foreach ($current_acl_ids as $current_acl_id) {
+ //Check to make sure these ACLs only have a single ACO mapped to them.
+ $current_acl_array = &$this->get_acl($current_acl_id);
+
+ //showarray($current_acl_array);
+ $this->debug_text("add_consolidated_acl(): Current Count: ".$this->count_all($current_acl_array['aco'])."");
+
+ if ( $this->count_all($current_acl_array['aco']) == 1) {
+ $this->debug_text("add_consolidated_acl(): ACL ID: $current_acl_id has 1 ACO.");
+
+ //Test to see if the return values match, if they do, no need removing or appending ARO. Just return true.
+ if ($current_acl_array['return_value'] == $return_value) {
+ $this->debug_text("add_consolidated_acl(): ACL ID: $current_acl_id has 1 ACO, and the same return value. No need to modify.");
+ return true;
+ }
+
+ $acl_ids[] = $current_acl_id;
+ }
+
+ }
+ }
+
+ //showarray($acl_ids);
+ $acl_ids_count = count($acl_ids);
+
+ //If acl_id's turns up more then one ACL, lets remove the ARO from all of them in hopes to
+ //eliminate any conflicts.
+ if (is_array($acl_ids) AND $acl_ids_count > 0) {
+ $this->debug_text("add_consolidated_acl(): Removing specified ARO from existing ACL.");
+
+ foreach ($acl_ids as $acl_id) {
+ //Remove ARO from current ACLs, so we don't create conflicting ACLs later on.
+ if (!$this->shift_acl($acl_id, array($aro_section_value => array($aro_value)) ) ) {
+ $this->debug_text("add_consolidated_acl(): Error removing specified ARO from ACL ID: $acl_id");
+ return false;
+ }
+ }
+ } else {
+ $this->debug_text("add_consolidated_acl(): Didn't find any current ACLs with a single ACO. ");
+ }
+ //unset($acl_ids);
+ $acl_ids = array();
+ unset($acl_ids_count);
+
+ //At this point there should be no conflicting ACLs, searching for an existing ACL with the new values.
+ $new_acl_ids = $this->search_acl($aco_section_value, $aco_value, FALSE, FALSE, NULL, NULL, NULL, NULL, $return_value);
+ $new_acl_count = count($new_acl_ids);
+ //showarray($new_acl_ids);
+
+ if (is_array($new_acl_ids)) {
+ $this->debug_text("add_consolidated_acl(): Found new ACL_IDs, counting ACOs");
+
+ foreach ($new_acl_ids as $new_acl_id) {
+ //Check to make sure these ACLs only have a single ACO mapped to them.
+ $new_acl_array = &$this->get_acl($new_acl_id);
+ //showarray($new_acl_array);
+ $this->debug_text("add_consolidated_acl(): New Count: ".$this->count_all($new_acl_array['aco'])."");
+ if ( $this->count_all($new_acl_array['aco']) == 1) {
+
+ $this->debug_text("add_consolidated_acl(): ACL ID: $new_acl_id has 1 ACO, append should be able to take place.");
+ $acl_ids[] = $new_acl_id;
+ }
+
+ }
+ }
+
+ //showarray($acl_ids);
+ $acl_ids_count = count($acl_ids);
+
+ if (is_array($acl_ids) AND $acl_ids_count == 1) {
+ $this->debug_text("add_consolidated_acl(): Appending specified ARO to existing ACL.");
+
+ $acl_id=$acl_ids[0];
+
+ if (!$this->append_acl($acl_id, array($aro_section_value => array($aro_value)) ) ) {
+ $this->debug_text("add_consolidated_acl(): Error appending specified ARO to ACL ID: $acl_id");
+ return false;
+ }
+
+ $this->debug_text("add_consolidated_acl(): Hot damn, ACL consolidated!");
+ return true;
+ } elseif($acl_ids_count > 1) {
+ $this->debug_text("add_consolidated_acl(): Found more then one ACL with a single ACO. Possible conflicting ACLs.");
+ return false;
+ } elseif ($acl_ids_count == 0) {
+ $this->debug_text("add_consolidated_acl(): No existing ACLs found, create a new one.");
+
+ if (!$this->add_acl( array( $aco_section_value => array($aco_value) ),
+ array( $aro_section_value => array($aro_value) ),
+ NULL,
+ NULL,
+ NULL,
+ TRUE,
+ TRUE,
+ $return_value,
+ NULL)
+ ) {
+ $this->debug_text("add_consolidated_acl(): Error adding new ACL for ACO Section: $aco_section_value ACO Value: $aco_value Return Value: $return_value");
+ return false;
+ }
+
+ $this->debug_text("add_consolidated_acl(): ADD_ACL() successfull, returning True.");
+ return true;
+ }
+
+ $this->debug_text("add_consolidated_acl(): Returning false.");
+ return false;
+ }
+
+ /**
+ * search_acl()
+ *
+ * Searches for ACL's with specified objects mapped to them.
+ *
+ * NULL values are included in the search, if you want to ignore
+ * for instance aro_groups use FALSE instead of NULL.
+ *
+ * @return array containing ACL IDs if search is successful
+ *
+ * @param string ACO Section Value
+ * @param string ACO Value
+ * @param string ARO Section Value
+ * @param string ARO Value
+ * @param string ARO Group Name
+ * @param string AXO Section Value
+ * @param string AXO Value
+ * @param string AXO Group Name
+ * @param string Return Value
+ */
+ function search_acl($aco_section_value=NULL, $aco_value=NULL, $aro_section_value=NULL, $aro_value=NULL, $aro_group_name=NULL, $axo_section_value=NULL, $axo_value=NULL, $axo_group_name=NULL, $return_value=NULL) {
+ $this->debug_text("search_acl(): aco_section_value: $aco_section_value aco_value: $aco_value, aro_section_value: $aro_section_value, aro_value: $aro_value, aro_group_name: $aro_group_name, axo_section_value: $axo_section_value, axo_value: $axo_value, axo_group_name: $axo_group_name, return_value: $return_value");
+
+ $query = '
+ SELECT a.id
+ FROM '. $this->_db_table_prefix .'acl a';
+
+ $where_query = array();
+
+ // ACO
+ if ($aco_section_value !== FALSE AND $aco_value !== FALSE) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'aco_map ac ON a.id=ac.acl_id';
+
+ if ($aco_section_value == NULL AND $aco_value == NULL) {
+ $where_query[] = '(ac.section_value IS NULL AND ac.value IS NULL)';
+ } else {
+ $where_query[] = '(ac.section_value='. $this->db->quote($aco_section_value) .' AND ac.value='. $this->db->quote($aco_value) .')';
+ }
+ }
+
+ // ARO
+ if ($aro_section_value !== FALSE AND $aro_value !== FALSE) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'aro_map ar ON a.id=ar.acl_id';
+
+ if ($aro_section_value == NULL AND $aro_value == NULL) {
+ $where_query[] = '(ar.section_value IS NULL AND ar.value IS NULL)';
+ } else {
+ $where_query[] = '(ar.section_value='. $this->db->quote($aro_section_value) .' AND ar.value='. $this->db->quote($aro_value) .')';
+ }
+ }
+
+ // AXO
+ if ($axo_section_value !== FALSE AND $axo_value !== FALSE) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'axo_map ax ON a.id=ax.acl_id';
+
+ if ($axo_section_value == NULL AND $axo_value == NULL) {
+ $where_query[] = '(ax.section_value IS NULL AND ax.value IS NULL)';
+ } else {
+ $where_query[] = '(ax.section_value='. $this->db->quote($axo_section_value) .' AND ax.value='. $this->db->quote($axo_value) .')';
+ }
+ }
+
+ // ARO Group
+ if ($aro_group_name !== FALSE) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'aro_groups_map arg ON a.id=arg.acl_id
+ LEFT JOIN '. $this->_db_table_prefix .'aro_groups rg ON arg.group_id=rg.id';
+
+ if ($aro_group_name == NULL) {
+ $where_query[] = '(rg.name IS NULL)';
+ } else {
+ $where_query[] = '(rg.name='. $this->db->quote($aro_group_name) .')';
+ }
+ }
+
+ // AXO Group
+ if ($axo_group_name !== FALSE) {
+ $query .= '
+ LEFT JOIN '. $this->_db_table_prefix .'axo_groups_map axg ON a.id=axg.acl_id
+ LEFT JOIN '. $this->_db_table_prefix .'axo_groups xg ON axg.group_id=xg.id';
+
+ if ($axo_group_name == NULL) {
+ $where_query[] = '(xg.name IS NULL)';
+ } else {
+ $where_query[] = '(xg.name='. $this->db->quote($axo_group_name) .')';
+ }
+ }
+ if ($return_value != FALSE) {
+ if ($return_value == NULL) {
+ $where_query[] = '(a.return_value IS NULL)';
+ } else {
+ $where_query[] = '(a.return_value='. $this->db->quote($return_value) .')';
+ }
+ }
+
+ if (count($where_query) > 0) {
+ $query .= '
+ WHERE '. implode (' AND ', $where_query);
+ }
+
+ return $this->db->GetCol($query);
+ }
+
+ /**
+ * append_acl()
+ *
+ * Appends objects on to a specific ACL.
+ *
+ * @return bool TRUE if successful, FALSE otherwise.
+ *
+ * @param int ACL ID #
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ */
+ function append_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NULL, $axo_group_ids=NULL, $aco_array=NULL) {
+ $this->debug_text("append_acl(): ACL_ID: $acl_id");
+
+ $update = 0;
+
+ if (empty($acl_id)) {
+ $this->debug_text("append_acl(): No ACL_ID specified! ACL_ID: $acl_id");
+ return false;
+ }
+
+ //Grab ACL data.
+ $acl_array = &$this->get_acl($acl_id);
+
+ //Append each object type seperately.
+ if (is_array($aro_array) AND count($aro_array) > 0) {
+ $this->debug_text("append_acl(): Appending ARO's");
+
+ while (list($aro_section_value,$aro_value_array) = @each($aro_array)) {
+ foreach ($aro_value_array as $aro_value) {
+ if ( count($acl_array['aro'][$aro_section_value]) != 0 ) {
+ if (!in_array($aro_value, $acl_array['aro'][$aro_section_value])) {
+ $this->debug_text("append_acl(): ARO Section Value: $aro_section_value ARO VALUE: $aro_value");
+ $acl_array['aro'][$aro_section_value][] = $aro_value;
+ $update=1;
+ } else {
+ $this->debug_text("append_acl(): Duplicate ARO, ignoring... ");
+ }
+ } else { //Array is empty so add this aro value.
+ $acl_array['aro'][$aro_section_value][] = $aro_value;
+ $update = 1;
+ }
+ }
+ }
+ }
+
+ if (is_array($aro_group_ids) AND count($aro_group_ids) > 0) {
+ $this->debug_text("append_acl(): Appending ARO_GROUP_ID's");
+
+ while (list(,$aro_group_id) = @each($aro_group_ids)) {
+ if (!is_array($acl_array['aro_groups']) OR !in_array($aro_group_id, $acl_array['aro_groups'])) {
+ $this->debug_text("append_acl(): ARO Group ID: $aro_group_id");
+ $acl_array['aro_groups'][] = $aro_group_id;
+ $update = 1;
+ } else {
+ $this->debug_text("append_acl(): Duplicate ARO_Group_ID, ignoring... ");
+ }
+ }
+ }
+
+ if (is_array($axo_array) AND count($axo_array) > 0) {
+ $this->debug_text("append_acl(): Appending AXO's");
+
+ while (list($axo_section_value,$axo_value_array) = @each($axo_array)) {
+ foreach ($axo_value_array as $axo_value) {
+ if (!in_array($axo_value, $acl_array['axo'][$axo_section_value])) {
+ $this->debug_text("append_acl(): AXO Section Value: $axo_section_value AXO VALUE: $axo_value");
+ $acl_array['axo'][$axo_section_value][] = $axo_value;
+ $update = 1;
+ } else {
+ $this->debug_text("append_acl(): Duplicate AXO, ignoring... ");
+ }
+
+ }
+ }
+ }
+
+ if (is_array($axo_group_ids) AND count($axo_group_ids) > 0) {
+ $this->debug_text("append_acl(): Appending AXO_GROUP_ID's");
+ while (list(,$axo_group_id) = @each($axo_group_ids)) {
+ if (!is_array($acl_array['axo_groups']) OR !in_array($axo_group_id, $acl_array['axo_groups'])) {
+ $this->debug_text("append_acl(): AXO Group ID: $axo_group_id");
+ $acl_array['axo_groups'][] = $axo_group_id;
+ $update = 1;
+ } else {
+ $this->debug_text("append_acl(): Duplicate ARO_Group_ID, ignoring... ");
+ }
+ }
+ }
+
+ if (is_array($aco_array) AND count($aco_array) > 0) {
+ $this->debug_text("append_acl(): Appending ACO's");
+
+ while (list($aco_section_value,$aco_value_array) = @each($aco_array)) {
+ foreach ($aco_value_array as $aco_value) {
+ if (!in_array($aco_value, $acl_array['aco'][$aco_section_value])) {
+ $this->debug_text("append_acl(): ACO Section Value: $aco_section_value ACO VALUE: $aco_value");
+ $acl_array['aco'][$aco_section_value][] = $aco_value;
+ $update = 1;
+ } else {
+ $this->debug_text("append_acl(): Duplicate ACO, ignoring... ");
+ }
+ }
+ }
+ }
+
+ if ($update == 1) {
+ $this->debug_text("append_acl(): Update flag set, updating ACL.");
+ //function edit_acl($acl_id, $aco_array, $aro_array, $aro_group_ids=NULL, $axo_array=NULL, $axo_group_ids=NULL, $allow=1, $enabled=1, $return_value=NULL, $note=NULL) {
+ return $this->edit_acl($acl_id, $acl_array['aco'], $acl_array['aro'], $acl_array['aro_groups'], $acl_array['axo'], $acl_array['axo_groups'], $acl_array['allow'], $acl_array['enabled'], $acl_array['return_value'], $acl_array['note']);
+ }
+
+ //Return true if everything is duplicate and no ACL id updated.
+ $this->debug_text("append_acl(): Update flag not set, NOT updating ACL.");
+ return true;
+ }
+
+ /**
+ * shift_acl()
+ *
+ * Opposite of append_acl(). Removes objects from a specific ACL. (named after PHP's array_shift())
+ *
+ * @return bool TRUE if successful, FALSE otherwise.
+ *
+ * @param int ACL ID #
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ */
+ function shift_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NULL, $axo_group_ids=NULL, $aco_array=NULL) {
+ $this->debug_text("shift_acl(): ACL_ID: $acl_id");
+
+ $update = 0;
+
+ if (empty($acl_id)) {
+ $this->debug_text("shift_acl(): No ACL_ID specified! ACL_ID: $acl_id");
+ return false;
+ }
+
+ //Grab ACL data.
+ $acl_array = &$this->get_acl($acl_id);
+
+ //showarray($acl_array);
+ //Remove each object type seperately.
+ if (is_array($aro_array) AND count($aro_array) > 0) {
+ $this->debug_text("shift_acl(): Removing ARO's");
+
+ while (list($aro_section_value,$aro_value_array) = @each($aro_array)) {
+ foreach ($aro_value_array as $aro_value) {
+ $this->debug_text("shift_acl(): ARO Section Value: $aro_section_value ARO VALUE: $aro_value");
+
+ //Only search if aro array contains data.
+ if ( count($acl_array['aro'][$aro_section_value]) != 0 ) {
+ $aro_key = array_search($aro_value, $acl_array['aro'][$aro_section_value]);
+
+ if ($aro_key !== FALSE) {
+ $this->debug_text("shift_acl(): Removing ARO. ($aro_key)");
+ unset($acl_array['aro'][$aro_section_value][$aro_key]);
+ $update = 1;
+ } else {
+ $this->debug_text("shift_acl(): ARO doesn't exist, can't remove it.");
+ }
+ }
+
+ }
+ }
+ }
+
+ if (is_array($aro_group_ids) AND count($aro_group_ids) > 0) {
+ $this->debug_text("shift_acl(): Removing ARO_GROUP_ID's");
+
+ while (list(,$aro_group_id) = @each($aro_group_ids)) {
+ $this->debug_text("shift_acl(): ARO Group ID: $aro_group_id");
+ $aro_group_key = array_search($aro_group_id, $acl_array['aro_groups']);
+
+ if ($aro_group_key !== FALSE) {
+ $this->debug_text("shift_acl(): Removing ARO Group. ($aro_group_key)");
+ unset($acl_array['aro_groups'][$aro_group_key]);
+ $update = 1;
+ } else {
+ $this->debug_text("shift_acl(): ARO Group doesn't exist, can't remove it.");
+ }
+ }
+ }
+
+ if (is_array($axo_array) AND count($axo_array) > 0) {
+ $this->debug_text("shift_acl(): Removing AXO's");
+
+ while (list($axo_section_value,$axo_value_array) = @each($axo_array)) {
+ foreach ($axo_value_array as $axo_value) {
+ $this->debug_text("shift_acl(): AXO Section Value: $axo_section_value AXO VALUE: $axo_value");
+ $axo_key = array_search($axo_value, $acl_array['axo'][$axo_section_value]);
+
+ if ($axo_key !== FALSE) {
+ $this->debug_text("shift_acl(): Removing AXO. ($axo_key)");
+ unset($acl_array['axo'][$axo_section_value][$axo_key]);
+ $update = 1;
+ } else {
+ $this->debug_text("shift_acl(): AXO doesn't exist, can't remove it.");
+ }
+ }
+ }
+ }
+
+ if (is_array($axo_group_ids) AND count($axo_group_ids) > 0) {
+ $this->debug_text("shift_acl(): Removing AXO_GROUP_ID's");
+
+ while (list(,$axo_group_id) = @each($axo_group_ids)) {
+ $this->debug_text("shift_acl(): AXO Group ID: $axo_group_id");
+ $axo_group_key = array_search($axo_group_id, $acl_array['axo_groups']);
+
+ if ($axo_group_key !== FALSE) {
+ $this->debug_text("shift_acl(): Removing AXO Group. ($axo_group_key)");
+ unset($acl_array['axo_groups'][$axo_group_key]);
+ $update = 1;
+ } else {
+ $this->debug_text("shift_acl(): AXO Group doesn't exist, can't remove it.");
+ }
+ }
+ }
+
+ if (is_array($aco_array) AND count($aco_array) > 0) {
+ $this->debug_text("shift_acl(): Removing ACO's");
+
+ while (list($aco_section_value,$aco_value_array) = @each($aco_array)) {
+ foreach ($aco_value_array as $aco_value) {
+ $this->debug_text("shift_acl(): ACO Section Value: $aco_section_value ACO VALUE: $aco_value");
+ $aco_key = array_search($aco_value, $acl_array['aco'][$aco_section_value]);
+
+ if ($aco_key !== FALSE) {
+ $this->debug_text("shift_acl(): Removing ACO. ($aco_key)");
+ unset($acl_array['aco'][$aco_section_value][$aco_key]);
+ $update = 1;
+ } else {
+ $this->debug_text("shift_acl(): ACO doesn't exist, can't remove it.");
+ }
+ }
+ }
+ }
+
+ if ($update == 1) {
+ //We know something was changed, so lets see if no ACO's or no ARO's are left assigned to this ACL, if so, delete the ACL completely.
+ //$this->showarray($acl_array);
+ $this->debug_text("shift_acl(): ACOs: ". $this->count_all($acl_array['aco']) ." AROs: ".$this->count_all($acl_array['aro'])."");
+
+ if ( $this->count_all($acl_array['aco']) == 0
+ OR ( $this->count_all($acl_array['aro']) == 0
+ AND ( $this->count_all($acl_array['axo']) == 0 OR $acl_array['axo'] == FALSE)
+ AND (count($acl_array['aro_groups']) == 0 OR $acl_array['aro_groups'] == FALSE)
+ AND (count($acl_array['axo_groups']) == 0 OR $acl_array['axo_groups'] == FALSE)
+ ) ) {
+ $this->debug_text("shift_acl(): No ACOs or ( AROs AND AXOs AND ARO Groups AND AXO Groups) left assigned to this ACL (ID: $acl_id), deleting ACL.");
+
+ return $this->del_acl($acl_id);
+ }
+
+ $this->debug_text("shift_acl(): Update flag set, updating ACL.");
+
+ return $this->edit_acl($acl_id, $acl_array['aco'], $acl_array['aro'], $acl_array['aro_groups'], $acl_array['axo'], $acl_array['axo_groups'], $acl_array['allow'], $acl_array['enabled'], $acl_array['return_value'], $acl_array['note']);
+ }
+
+ //Return true if everything is duplicate and no ACL id updated.
+ $this->debug_text("shift_acl(): Update flag not set, NOT updating ACL.");
+ return true;
+ }
+
+ /**
+ * get_acl()
+ *
+ * Grabs ACL data.
+ *
+ * @return bool FALSE if not found, or Associative Array with the following items:
+ *
+ * - 'aco' => Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * - 'aro' => Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * - 'axo' => Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * - 'aro_groups' => Array of Group IDs
+ * - 'axo_groups' => Array of Group IDs
+ * - 'acl_id' => int ACL ID #
+ * - 'allow' => int Allow flag
+ * - 'enabled' => int Enabled flag
+ * - 'return_value' => string Return Value
+ * - 'note' => string Note
+ *
+ * @param int ACL ID #
+ */
+ function get_acl($acl_id) {
+
+ $this->debug_text("get_acl(): ACL_ID: $acl_id");
+
+ if (empty($acl_id)) {
+ $this->debug_text("get_acl(): No ACL_ID specified! ACL_ID: $acl_id");
+ return false;
+ }
+
+ //Grab ACL information
+ $query = "select id, allow, enabled, return_value, note from ".$this->_db_table_prefix."acl where id = ".$acl_id."";
+ $acl_row = $this->db->GetRow($query);
+
+ // return false if not found
+ if (!$acl_row) {
+ $this->debug_text("get_acl(): No ACL found for that ID! ACL_ID: $acl_id");
+ return false;
+ }
+
+ list($retarr['acl_id'], $retarr['allow'], $retarr['enabled'], $retarr['return_value'], $retarr['note']) = $acl_row;
+
+ //Grab selected ACO's
+ $query = "select distinct a.section_value, a.value, c.name, b.name from ".$this->_db_table_prefix."aco_map a, ".$this->_db_table_prefix."aco b, ".$this->_db_table_prefix."aco_sections c
+ where ( a.section_value=b.section_value AND a.value = b.value) AND b.section_value=c.value AND a.acl_id = $acl_id";
+ $rs = $this->db->Execute($query);
+ $rows = $rs->GetRows();
+
+ $retarr['aco'] = array();
+ while (list(,$row) = @each($rows)) {
+ list($section_value, $value, $section, $aco) = $row;
+ $this->debug_text("Section Value: $section_value Value: $value Section: $section ACO: $aco");
+
+ $retarr['aco'][$section_value][] = $value;
+
+ }
+ //showarray($aco);
+
+ //Grab selected ARO's
+ $query = "select distinct a.section_value, a.value, c.name, b.name from ".$this->_db_table_prefix."aro_map a, ".$this->_db_table_prefix."aro b, ".$this->_db_table_prefix."aro_sections c
+ where ( a.section_value=b.section_value AND a.value = b.value) AND b.section_value=c.value AND a.acl_id = $acl_id";
+ $rs = $this->db->Execute($query);
+ $rows = $rs->GetRows();
+
+ $retarr['aro'] = array();
+ while (list(,$row) = @each($rows)) {
+ list($section_value, $value, $section, $aro) = $row;
+ $this->debug_text("Section Value: $section_value Value: $value Section: $section ARO: $aro");
+
+ $retarr['aro'][$section_value][] = $value;
+
+ }
+ //showarray($options_aro);
+
+ //Grab selected AXO's
+ $query = "select distinct a.section_value, a.value, c.name, b.name from ".$this->_db_table_prefix."axo_map a, ".$this->_db_table_prefix."axo b, ".$this->_db_table_prefix."axo_sections c
+ where ( a.section_value=b.section_value AND a.value = b.value) AND b.section_value=c.value AND a.acl_id = $acl_id";
+ $rs = $this->db->Execute($query);
+ $rows = $rs->GetRows();
+
+ $retarr['axo'] = array();
+ while (list(,$row) = @each($rows)) {
+ list($section_value, $value, $section, $axo) = $row;
+ $this->debug_text("Section Value: $section_value Value: $value Section: $section AXO: $axo");
+
+ $retarr['axo'][$section_value][] = $value;
+
+ }
+ //showarray($options_aro);
+
+ //Grab selected ARO groups.
+ $retarr['aro_groups'] = array();
+ $query = "select distinct group_id from ".$this->_db_table_prefix."aro_groups_map where acl_id = $acl_id";
+ $retarr['aro_groups'] = $this->db->GetCol($query);
+ //showarray($selected_groups);
+
+ //Grab selected AXO groups.
+ $retarr['axo_groups'] = array();
+ $query = "select distinct group_id from ".$this->_db_table_prefix."axo_groups_map where acl_id = $acl_id";
+ $retarr['axo_groups'] = $this->db->GetCol($query);
+ //showarray($selected_groups);
+
+ return $retarr;
+ }
+
+ /**
+ * is_conflicting_acl()
+ *
+ * Checks for conflicts when adding a specific ACL.
+ *
+ * @return bool Returns true if conflict is found.
+ *
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param array Array of ACL IDs to ignore from the result set.
+ *
+ */
+ function is_conflicting_acl($aco_array, $aro_array, $aro_group_ids=NULL, $axo_array=NULL, $axo_group_ids=NULL, $ignore_acl_ids=NULL) {
+ //Check for potential conflicts. Ignore groups, as groups will almost always have "conflicting" ACLs.
+ //Thats part of inheritance.
+
+ if (!is_array($aco_array)) {
+ $this->debug_text('is_conflicting_acl(): Invalid ACO Array.');
+ return FALSE;
+ }
+
+ if (!is_array($aro_array)) {
+ $this->debug_text('is_conflicting_acl(): Invalid ARO Array.');
+ return FALSE;
+ }
+
+ $query = '
+ SELECT a.id
+ FROM '. $this->_db_table_prefix .'acl a
+ LEFT JOIN '. $this->_db_table_prefix .'aco_map ac ON ac.acl_id=a.id
+ LEFT JOIN '. $this->_db_table_prefix .'aro_map ar ON ar.acl_id=a.id
+ LEFT JOIN '. $this->_db_table_prefix .'axo_map ax ON ax.acl_id=a.id
+ LEFT JOIN '. $this->_db_table_prefix .'axo_groups_map axg ON axg.acl_id=a.id
+ LEFT JOIN '. $this->_db_table_prefix .'axo_groups xg ON xg.id=axg.group_id
+ ';
+
+ //ACO
+ foreach ($aco_array as $aco_section_value => $aco_value_array) {
+ $this->debug_text("is_conflicting_acl(): ACO Section Value: $aco_section_value ACO VALUE: $aco_value_array");
+ //showarray($aco_array);
+
+ if (!is_array($aco_value_array)) {
+ $this->debug_text('is_conflicting_acl(): Invalid Format for ACO Array item. Skipping...');
+ continue;
+ // return TRUE;
+ }
+ //Move the below line in to the LEFT JOIN above for PostgreSQL sake.
+ //'ac1' => 'ac.acl_id=a.id',
+ $where_query = array(
+ 'ac2' => '(ac.section_value='. $this->db->quote($aco_section_value) .' AND ac.value IN (\''. implode ('\',\'', $aco_value_array) .'\'))'
+ );
+
+ //ARO
+ foreach ($aro_array as $aro_section_value => $aro_value_array) {
+ $this->debug_text("is_conflicting_acl(): ARO Section Value: $aro_section_value ARO VALUE: $aro_value_array");
+
+ if (!is_array($aro_value_array))
+ {
+ $this->debug_text('is_conflicting_acl(): Invalid Format for ARO Array item. Skipping...');
+ continue;
+ // return TRUE;
+ }
+
+ $this->debug_text("is_conflicting_acl(): Search: ACO Section: $aco_section_value ACO Value: $aco_value_array ARO Section: $aro_section_value ARO Value: $aro_value_array");
+
+ //Move the below line in to the LEFT JOIN above for PostgreSQL sake.
+ //$where_query['ar1'] = 'ar.acl_id=a.id';
+ $where_query['ar2'] = '(ar.section_value='. $this->db->quote($aro_section_value) .' AND ar.value IN (\''. implode ('\',\'', $aro_value_array) .'\'))';
+
+ if (is_array($axo_array) AND count($axo_array) > 0) {
+ foreach ($axo_array as $axo_section_value => $axo_value_array) {
+ $this->debug_text("is_conflicting_acl(): AXO Section Value: $axo_section_value AXO VALUE: $axo_value_array");
+
+ if (!is_array($axo_value_array)) {
+ $this->debug_text('is_conflicting_acl(): Invalid Format for AXO Array item. Skipping...');
+ continue;
+ // return TRUE;
+ }
+
+ $this->debug_text("is_conflicting_acl(): Search: ACO Section: $aco_section_value ACO Value: $aco_value_array ARO Section: $aro_section_value ARO Value: $aro_value_array AXO Section: $axo_section_value AXO Value: $axo_value_array");
+
+ //$where_query['ax1'] = 'ax.acl_id=x.id';
+ $where_query['ax1'] = 'ax.acl_id=a.id';
+ $where_query['ax2'] = '(ax.section_value='. $this->db->quote($axo_section_value) .' AND ax.value IN (\''. implode ('\',\'', $axo_value_array) .'\'))';
+
+ $where = 'WHERE ' . implode(' AND ', $where_query);
+
+ $conflict_result = $this->db->GetCol($query . $where);
+
+ if (is_array($conflict_result) AND !empty($conflict_result)) {
+ // showarray($conflict_result);
+
+ if (is_array($ignore_acl_ids)) {
+ $conflict_result = array_diff($conflict_result, $ignore_acl_ids);
+ }
+
+ if (count($conflict_result) > 0) {
+ $conflicting_acls_str = implode(',', $conflict_result);
+ $this->debug_text("is_conflicting_acl(): Conflict FOUND!!! ACL_IDS: ($conflicting_acls_str)");
+ return TRUE;
+ }
+ }
+ }
+ } else {
+ $where_query['ax1'] = '(ax.section_value IS NULL AND ax.value IS NULL)';
+ $where_query['ax2'] = 'xg.name IS NULL';
+
+ $where = 'WHERE ' . implode(' AND ', $where_query);
+
+ $conflict_result = $this->db->GetCol($query . $where);
+
+ if (is_array($conflict_result) AND !empty($conflict_result)) {
+ // showarray($conflict_result);
+
+ if (is_array($ignore_acl_ids)) {
+ $conflict_result = array_diff($conflict_result, $ignore_acl_ids);
+ }
+
+ if (count($conflict_result) > 0) {
+ $conflicting_acls_str = implode(',', $conflict_result);
+ $this->debug_text("is_conflicting_acl(): Conflict FOUND!!! ACL_IDS: ($conflicting_acls_str)");
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ $this->debug_text('is_conflicting_acl(): No conflicting ACL found.');
+ return FALSE;
+ }
+
+ /**
+ * add_acl()
+ *
+ * Add's an ACL. ACO_IDS, ARO_IDS, GROUP_IDS must all be arrays.
+ *
+ * @return bool Return ACL ID of new ACL if successful, FALSE otherewise.
+ *
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param int Allow flag
+ * @param int Enabled flag
+ * @param string Return Value
+ * @param string Note
+ * @param string ACL Section Value
+ * @param int ACL ID # Specific Request
+
+ */
+ function add_acl($aco_array, $aro_array, $aro_group_ids=NULL, $axo_array=NULL, $axo_group_ids=NULL, $allow=1, $enabled=1, $return_value=NULL, $note=NULL, $section_value=NULL, $acl_id=FALSE ) {
+
+ $this->debug_text("add_acl():");
+
+ if (count($aco_array) == 0) {
+ $this->debug_text("Must select at least one Access Control Object");
+ return false;
+ }
+
+ if (count($aro_array) == 0 AND count($aro_group_ids) == 0) {
+ $this->debug_text("Must select at least one Access Request Object or Group");
+ return false;
+ }
+
+ if (empty($allow)) {
+ $allow=0;
+ }
+
+ if (empty($enabled)) {
+ $enabled=0;
+ }
+
+ if (!empty($section_value)
+ AND !$this->get_object_section_section_id(NULL, $section_value, 'ACL')) {
+ $this->debug_text("add_acl(): Section Value: $section_value DOES NOT exist in the database.");
+ return false;
+ }
+
+ //Unique the group arrays. Later one we unique ACO/ARO/AXO arrays.
+ if (is_array($aro_group_ids)) {
+ $aro_group_ids = array_unique($aro_group_ids);
+ }
+ if (is_array($axo_group_ids)) {
+ $axo_group_ids = array_unique($axo_group_ids);
+ }
+
+ //Check for conflicting ACLs.
+ if ($this->is_conflicting_acl($aco_array,$aro_array,$aro_group_ids,$axo_array,$axo_group_ids,array($acl_id))) {
+ $this->debug_text("add_acl(): Detected possible ACL conflict, not adding ACL!");
+ return false;
+ }
+
+ //Edit ACL if acl_id is set. This is simply if we're being called by edit_acl().
+ if ($this->get_acl($acl_id) == FALSE) {
+ if ( empty($section_value) ) {
+ $section_value='system';
+ if( !$this->get_object_section_section_id(NULL, $section_value, 'ACL') ) {
+ // Use the acl section with the lowest order value.
+ $acl_sections_table = $this->_db_table_prefix .'acl_sections';
+ $acl_section_order_value = $this->db->GetOne("SELECT min(order_value) from $acl_sections_table");
+
+ $query = "
+ SELECT value
+ FROM $acl_sections_table
+ WHERE order_value = $acl_section_order_value
+ ";
+ $section_value = $this->db->GetOne($query);
+
+ if ( empty($section_value) ) {
+ $this->debug_text("add_acl(): No valid acl section found.");
+ return false;
+ } else {
+ $this->debug_text("add_acl(): Using default section value: $section_value.");
+ }
+ }
+ }
+
+ //ACL not specified, so create acl_id
+ if (empty($acl_id)) {
+ //Create ACL row first, so we have the acl_id
+ $acl_id = $this->db->GenID($this->_db_table_prefix.'acl_seq',10);
+
+ //Double check the ACL ID was generated.
+ if (empty($acl_id)) {
+ $this->debug_text("add_acl(): ACL_ID generation failed!");
+ return false;
+ }
+ }
+
+ //Begin transaction _after_ GenID. Because on the first run, if GenID has to create the sequence,
+ //the transaction will fail.
+ $this->db->BeginTrans();
+
+ $query = 'INSERT INTO '.$this->_db_table_prefix.'acl (id,section_value,allow,enabled,return_value,note,updated_date) VALUES('. $acl_id .','. $this->db->quote($section_value) .','. $allow .','. $enabled .','. $this->db->quote($return_value) .', '. $this->db->quote($note) .','. time() .')';
+ $result = $this->db->Execute($query);
+ } else {
+ $section_sql = '';
+ if ( !empty($section_value) ) {
+ $section_sql = 'section_value='. $this->db->quote ($section_value) .',';
+ }
+
+ $this->db->BeginTrans();
+
+ //Update ACL row, and remove all mappings so they can be re-inserted.
+ $query = '
+ UPDATE '. $this->_db_table_prefix .'acl
+ SET ' . $section_sql . '
+ allow='. $allow .',
+ enabled='. $enabled .',
+ return_value='. $this->db->quote($return_value) .',
+ note='. $this->db->quote($note) .',
+ updated_date='. time() .'
+ WHERE id='. $acl_id;
+ $result = $this->db->Execute($query);
+
+ if ($result) {
+ $this->debug_text("Update completed without error, delete mappings...");
+ //Delete all mappings so they can be re-inserted.
+ foreach (array('aco_map', 'aro_map', 'axo_map', 'aro_groups_map', 'axo_groups_map') as $map) {
+ $query = 'DELETE FROM '. $this->_db_table_prefix . $map .' WHERE acl_id='. $acl_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs))
+ {
+ $this->debug_db('add_acl');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ if (!is_object($result)) {
+ $this->debug_db('add_acl');
+ $this->db->RollBackTrans();
+ return false;
+ }
+
+ $this->debug_text("Insert or Update completed without error, insert new mappings.");
+ // Insert ACO/ARO/AXO mappings
+ foreach (array('aco', 'aro', 'axo') as $map) {
+ $map_array = ${$map .'_array'};
+
+ if (!is_array ($map_array)) {
+ continue;
+ }
+
+ foreach ($map_array as $section_value => $value_array) {
+ $this->debug_text ('Insert: '. strtoupper($map) .' Section Value: '. $section_value .' '. strtoupper($map) .' VALUE: '. $value_array);
+ // $this->showarray ($aco_value_array);
+
+ if (!is_array($value_array)) {
+ $this->debug_text ('add_acl (): Invalid Format for '. strtoupper ($map) .' Array item. Skipping...');
+ continue;
+ // return true;
+ }
+
+ $value_array = array_unique($value_array);
+
+ foreach ($value_array as $value) {
+ $object_id = &$this->get_object_id($section_value, $value, $map);
+
+ if (empty($object_id))
+ {
+ $this->debug_text('add_acl(): '. strtoupper($map) . " Object Section Value: $section_value Value: $value DOES NOT exist in the database. Skipping...");
+ $this->db->RollBackTrans();
+ return false;
+ }
+
+ $query = 'INSERT INTO '. $this->_db_table_prefix . $map .'_map (acl_id,section_value,value) VALUES ('. $acl_id .', '. $this->db->quote($section_value) .', '. $this->db->quote($value) .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs))
+ {
+ $this->debug_db('add_acl');
+ $this->db->RollBackTrans();
+ return false;
+ }
+ }
+ }
+ }
+
+ // Insert ARO/AXO GROUP mappings
+ foreach (array('aro', 'axo') as $map) {
+ $map_group_ids = ${$map .'_group_ids'};
+
+ if (!is_array($map_group_ids)) {
+ continue;
+ }
+
+ foreach ($map_group_ids as $group_id) {
+ $this->debug_text ('Insert: '. strtoupper($map) .' GROUP ID: '. $group_id);
+
+ $group_data = &$this->get_group_data($group_id, $map);
+
+ if (empty($group_data)) {
+ $this->debug_text('add_acl(): '. strtoupper($map) . " Group: $group_id DOES NOT exist in the database. Skipping...");
+ $this->db->RollBackTrans();
+ return false;
+ }
+
+ $query = 'INSERT INTO '. $this->_db_table_prefix . $map .'_groups_map (acl_id,group_id) VALUES ('. $acl_id .', '. $group_id .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_acl');
+ $this->db->RollBackTrans();
+ return false;
+ }
+ }
+ }
+
+ $this->db->CommitTrans();
+
+ if ($this->_caching == TRUE AND $this->_force_cache_expire == TRUE) {
+ //Expire all cache.
+ $this->Cache_Lite->clean('default');
+ }
+
+ //Return only the ID in the first row.
+ return $acl_id;
+ }
+
+ /**
+ * edit_acl()
+ *
+ * Edit's an ACL, ACO_IDS, ARO_IDS, GROUP_IDS must all be arrays.
+ *
+ * @return bool Return TRUE if successful, FALSE otherewise.
+ *
+ * @param int ACL ID # to edit
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ * @param array Array of Group IDs
+ * @param int Allow flag
+ * @param int Enabled flag
+ * @param string Return Value
+ * @param string Note
+ * @param string ACL Section Value
+ */
+ function edit_acl($acl_id, $aco_array, $aro_array, $aro_group_ids=NULL, $axo_array=NULL, $axo_group_ids=NULL, $allow=1, $enabled=1, $return_value=NULL, $note=NULL, $section_value=NULL) {
+
+ $this->debug_text("edit_acl():");
+
+ if (empty($acl_id) ) {
+ $this->debug_text("edit_acl(): Must specify a single ACL_ID to edit");
+ return false;
+ }
+ if (count($aco_array) == 0) {
+ $this->debug_text("edit_acl(): Must select at least one Access Control Object");
+ return false;
+ }
+
+ if (count($aro_array) == 0 AND count($aro_group_ids) == 0) {
+ $this->debug_text("edit_acl(): Must select at least one Access Request Object or Group");
+ return false;
+ }
+
+ if (empty($allow)) {
+ $allow=0;
+ }
+
+ if (empty($enabled)) {
+ $enabled=0;
+ }
+
+ //if ($this->add_acl($aco_array, $aro_array, $group_ids, $allow, $enabled, $acl_id)) {
+ if ($this->add_acl($aco_array, $aro_array, $aro_group_ids, $axo_array, $axo_group_ids, $allow, $enabled, $return_value, $note, $section_value, $acl_id)) {
+ return true;
+ } else {
+ $this->debug_text("edit_acl(): error in add_acl()");
+ return false;
+ }
+ }
+
+ /**
+ * del_acl()
+ *
+ * Deletes a given ACL
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise.
+ *
+ * @param int ACL ID # to delete
+ */
+ function del_acl($acl_id) {
+
+ $this->debug_text("del_acl(): ID: $acl_id");
+
+ if (empty($acl_id) ) {
+ $this->debug_text("del_acl(): ACL_ID ($acl_id) is empty, this is required");
+ return false;
+ }
+
+ $this->db->BeginTrans();
+
+ // Delete all mappings to the ACL first
+ foreach (array('aco_map', 'aro_map', 'axo_map', 'aro_groups_map', 'axo_groups_map') as $map) {
+ $query = 'DELETE FROM '. $this->_db_table_prefix . $map .' WHERE acl_id='. $acl_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('del_acl');
+ $this->db->RollBackTrans();
+ return false;
+ }
+ }
+
+ // Delete the ACL
+ $query = 'DELETE FROM '. $this->_db_table_prefix .'acl WHERE id='. $acl_id;
+ $this->debug_text('delete query: '. $query);
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('del_acl');
+ $this->db->RollBackTrans();
+ return false;
+ }
+
+ $this->debug_text("del_acl(): deleted ACL ID: $acl_id");
+ $this->db->CommitTrans();
+
+ if ($this->_caching == TRUE AND $this->_force_cache_expire == TRUE) {
+ //Expire all cache.
+ $this->Cache_Lite->clean('default');
+ }
+
+ return TRUE;
+ }
+
+
+ /*
+ *
+ * Groups
+ *
+ */
+
+ /**
+ * sort_groups()
+ *
+ * Grabs all the groups from the database doing preliminary grouping by parent
+ *
+ * @return array Returns 2-Dimensional array: $array[<parent_id>][<group_id>] = <group_name>
+ *
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function sort_groups($group_type='ARO') {
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $table = $this->_db_table_prefix .'aro_groups';
+ break;
+ }
+
+ //Grab all groups from the database.
+ $query = 'SELECT id, parent_id, name FROM '. $table .' ORDER BY parent_id, name';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('sort_groups');
+ return false;
+ }
+
+ /*
+ * Save groups in an array sorted by parent. Should be make it easier for later on.
+ */
+ $sorted_groups = array();
+
+ while ($row = $rs->FetchRow()) {
+ $id = &$row[0];
+ $parent_id = &$row[1];
+ $name = &$row[2];
+
+ $sorted_groups[$parent_id][$id] = $name;
+ }
+
+ return $sorted_groups;
+ }
+
+ /**
+ * format_groups()
+ *
+ * Takes the array returned by sort_groups() and formats for human
+ * consumption. Recursively calls itself to produce the desired output.
+ *
+ * @return array Array of formatted text, ordered by group id, formatted according to $type
+ *
+ * @param array Output from gacl_api->sorted_groups($group_type)
+ * @param array Output type desired, either 'TEXT', 'HTML', or 'ARRAY'
+ * @param int Root of tree to produce
+ * @param int Current level of depth
+ * @param array Pass the current formatted groups object for appending via recursion.
+ */
+ function format_groups($sorted_groups, $type='TEXT', $root_id=0, $level=0, $formatted_groups=NULL) {
+ if ( !is_array ($sorted_groups) ) {
+ return FALSE;
+ }
+
+ if ( !is_array ($formatted_groups) ) {
+ $formatted_groups = array ();
+ }
+
+ //$this->showarray($formatted_groups);
+
+ //while (list($id,$name) = @each($sorted_groups[$root_id])) {
+ if (isset($sorted_groups[$root_id])) {
+ //$last_id = end( array_keys($sorted_groups[$root_id]));
+ //PHP5 compatibility
+ $keys = array_keys($sorted_groups[$root_id]);
+ $last_id = end($keys);
+ unset($keys);
+
+ foreach ($sorted_groups[$root_id] as $id => $name) {
+ switch (strtoupper($type)) {
+ case 'TEXT':
+ /*
+ * Formatting optimized for TEXT (combo box) output.
+ */
+
+ if ( is_numeric($level) ) {
+ $level = str_repeat('&nbsp;&nbsp; ', $level);
+ }
+
+ if ( strlen($level) >= 8 ) {
+ if ( $id == $last_id ) {
+ $spacing = substr($level, 0, -8) .'\'- ';
+ $level = substr($level, 0, -8) .'&nbsp;&nbsp; ';
+ } else {
+ $spacing = substr($level, 0, -8) .'|- ';
+ }
+ } else {
+ $spacing = $level;
+ }
+
+ $next = $level .'|&nbsp; ';
+ $text = $spacing.$name;
+ break;
+ case 'HTML':
+ /*
+ * Formatting optimized for HTML (tables) output.
+ */
+ $width= $level * 20;
+ $spacing = "<img src=\"s.gif\" width=\"$width\">";
+ $next = $level + 1;
+ $text = $spacing." ".$name;
+ break;
+ case 'ARRAY':
+ $next = $level;
+ $text = $name;
+ break;
+ default:
+ return FALSE;
+ }
+
+ $formatted_groups[$id] = $text;
+ /*
+ * Recurse if we can.
+ */
+
+ //if (isset($sorted_groups[$id]) AND count($sorted_groups[$id]) > 0) {
+ if (isset($sorted_groups[$id]) ) {
+ //$this->debug_text("format_groups(): Recursing! Level: $level");
+ $formatted_groups = $this->format_groups($sorted_groups, $type, $id, $next, $formatted_groups);
+ } else {
+ //$this->debug_text("format_groups(): Found last branch!");
+ }
+ }
+ }
+
+ //$this->debug_text("format_groups(): Returning final array.");
+
+ return $formatted_groups;
+ }
+
+ /**
+ * get_group_id()
+ *
+ * Gets the group_id given the name or value.
+ *
+ * Will only return one group id, so if there are duplicate names, it will return false.
+ *
+ * @return int Returns Group ID if found and Group ID is unique in database, otherwise, returns FALSE
+ *
+ * @param string Group Value
+ * @param string Group Name
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function get_group_id($value = NULL, $name = NULL, $group_type = 'ARO') {
+
+ $this->debug_text("get_group_id(): Value: $value, Name: $name, Type: $group_type" );
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $table = $this->_db_table_prefix .'aro_groups';
+ break;
+ }
+
+ $name = trim($name);
+ $value = trim($value);
+
+ if (empty($name) AND empty($value) ) {
+ $this->debug_text("get_group_id(): name and value, at least one is required");
+ return false;
+ }
+
+ $query = 'SELECT id FROM '. $table .' WHERE ';
+ if ( !empty($value) ) {
+ $query .= ' value='. $this->db->quote($value);
+ } else {
+ $query .= ' name='. $this->db->quote($name);
+ }
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_group_id');
+ return false;
+ }
+
+ $row_count = $rs->RecordCount();
+
+ if ($row_count > 1) {
+ $this->debug_text("get_group_id(): Returned $row_count rows, can only return one. Please make your names unique.");
+ return false;
+ }
+
+ if ($row_count == 0) {
+ $this->debug_text("get_group_id(): Returned $row_count rows");
+ return false;
+ }
+
+ $row = $rs->FetchRow();
+
+ //Return the ID.
+ return $row[0];
+ }
+
+ /**
+ * get_group_children()
+ *
+ * Gets a groups child IDs
+ *
+ * @return array Array of Child ID's of the referenced group
+ *
+ * @param int Group ID #
+ * @param int Group Type, either 'ARO' or 'AXO'
+ * @param string Either 'RECURSE' or 'NO_RECURSE', to recurse while fetching group children.
+ */
+ function get_group_children($group_id, $group_type = 'ARO', $recurse = 'NO_RECURSE') {
+ $this->debug_text("get_group_children(): Group_ID: $group_id Group Type: $group_type Recurse: $recurse");
+
+ switch (strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $group_type = 'aro';
+ $table = $this->_db_table_prefix .'aro_groups';
+ }
+
+ if (empty($group_id)) {
+ $this->debug_text("get_group_children(): ID ($group_id) is empty, this is required");
+ return FALSE;
+ }
+
+ $query = '
+ SELECT g1.id
+ FROM '. $table .' g1';
+
+ //FIXME-mikeb: Why is group_id in quotes?
+ switch (strtoupper($recurse)) {
+ case 'RECURSE':
+ $query .= '
+ LEFT JOIN '. $table .' g2 ON g2.lft<g1.lft AND g2.rgt>g1.rgt
+ WHERE g2.id='. $group_id;
+ break;
+ default:
+ $query .= '
+ WHERE g1.parent_id='. $group_id;
+ }
+
+ $query .= '
+ ORDER BY g1.value';
+
+ return $this->db->GetCol($query);
+ }
+
+ /**
+ * get_group_data()
+ *
+ * Gets the group data given the GROUP_ID.
+ *
+ * @return array Returns numerically indexed array with the following columns:
+ * - array[0] = (int) Group ID #
+ * - array[1] = (int) Parent Group ID #
+ * - array[2] = (string) Group Value
+ * - array[3] = (string) Group Name
+ * - array[4] = (int) lft MPTT Value
+ * - array[5] = (int) rgt MPTT Value
+ *
+ * @param int Group ID #
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function get_group_data($group_id, $group_type = 'ARO') {
+
+ $this->debug_text("get_group_data(): Group_ID: $group_id Group Type: $group_type");
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $group_type = 'aro';
+ $table = $this->_db_table_prefix .'aro_groups';
+ break;
+ }
+
+ if (empty($group_id) ) {
+ $this->debug_text("get_group_data(): ID ($group_id) is empty, this is required");
+ return false;
+ }
+
+ $query = 'SELECT id, parent_id, value, name, lft, rgt FROM '. $table .' WHERE id='. $group_id;
+ //$rs = $this->db->Execute($query);
+ $row = $this->db->GetRow($query);
+
+ if ($row) {
+ return $row;
+ }
+
+ $this->debug_text("get_object_data(): Group does not exist.");
+ return false;
+ }
+
+ /**
+ * get_group_parent_id()
+ *
+ * Grabs the parent_id of a given group
+ *
+ * @return int Parent ID of the Group
+ *
+ * @param int Group ID #
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function get_group_parent_id($id, $group_type='ARO') {
+
+ $this->debug_text("get_group_parent_id(): ID: $id Group Type: $group_type");
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $table = $this->_db_table_prefix .'aro_groups';
+ break;
+ }
+
+ if (empty($id) ) {
+ $this->debug_text("get_group_parent_id(): ID ($id) is empty, this is required");
+ return false;
+ }
+
+ $query = 'SELECT parent_id FROM '. $table .' WHERE id='. $id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_group_parent_id');
+ return false;
+ }
+
+ $row_count = $rs->RecordCount();
+
+ if ($row_count > 1) {
+ $this->debug_text("get_group_parent_id(): Returned $row_count rows, can only return one. Please make your names unique.");
+ return false;
+ }
+
+ if ($row_count == 0) {
+ $this->debug_text("get_group_parent_id(): Returned $row_count rows");
+ return false;
+ }
+
+ $row = $rs->FetchRow();
+
+ //Return the ID.
+ return $row[0];
+ }
+
+
+ /**
+ * get_root_group_id ()
+ *
+ * Grabs the id of the root group for the specified tree
+ *
+ * @return int Root Group ID #
+ *
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function get_root_group_id($group_type='ARO') {
+
+ $this->debug_text('get_root_group_id(): Group Type: '. $group_type);
+
+ switch (strtolower($group_type)) {
+ case 'axo':
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ case 'aro':
+ $table = $this->_db_table_prefix .'aro_groups';
+ break;
+ default:
+ $this->debug_text('get_root_group_id(): Invalid Group Type: '. $group_type);
+ return FALSE;
+ }
+
+ $query = 'SELECT id FROM '. $table .' WHERE parent_id=0';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_root_group_id');
+ return FALSE;
+ }
+
+ $row_count = $rs->RecordCount();
+
+ switch ($row_count) {
+ case 1:
+ $row = $rs->FetchRow();
+ // Return the ID.
+ return $row[0];
+ case 0:
+ $this->debug_text('get_root_group_id(): Returned 0 rows, you do not have a root group defined yet.');
+ return FALSE;
+ }
+
+ $this->debug_text('get_root_group_id(): Returned '. $row_count .' rows, can only return one. Your tree is very broken.');
+ return FALSE;
+ }
+
+ /*======================================================================*\
+ Function: map_path_to_root()
+ Purpose: Maps a unique path to root to a specific group. Each group can only have
+ one path to root.
+ \*======================================================================*/
+ /** REMOVED **/
+ /*======================================================================*\
+ Function: put_path_to_root()
+ Purpose: Writes the unique path to root to the database. There should really only be
+ one path to root for each level "deep" the groups go. If the groups are branched
+ 10 levels deep, there should only be 10 unique path to roots. These of course
+ overlap each other more and more the closer to the root/trunk they get.
+ \*======================================================================*/
+ /** REMOVED **/
+ /*======================================================================*\
+ Function: clean_path_to_root()
+ Purpose: Cleans up any paths that are not being used.
+ \*======================================================================*/
+ /** REMOVED **/
+ /*======================================================================*\
+ Function: get_path_to_root()
+ Purpose: Generates the path to root for a given group.
+ \*======================================================================*/
+ /** REMOVED **/
+
+ /**
+ * add_group()
+ *
+ * Inserts a group, defaults to be on the "root" branch.
+ *
+ * Since v3.3.x you can only create one group with Parent_ID=0
+ * So, its a good idea to create a "Virtual Root" group with Parent_ID=0
+ * Then assign other groups to that.
+ *
+ * @return int New Group ID # if successful, FALSE if otherwise.
+ *
+ * @param string Group Value
+ * @param string Group Name
+ * @param int Parent Group ID #
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function add_group($value, $name, $parent_id=0, $group_type='ARO') {
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $group_type = 'aro';
+ $table = $this->_db_table_prefix .'aro_groups';
+ break;
+ }
+
+ $this->debug_text("add_group(): Name: $name Value: $value Parent ID: $parent_id Group Type: $group_type");
+
+ $name = trim($name);
+ $value = trim($value);
+
+ if ( $name == '' ) {
+ $this->debug_text("add_group(): name ($name) OR parent id ($parent_id) is empty, this is required");
+ return false;
+ }
+
+ //This has to be outside the transaction, because the first time it is run, it will say the sequence
+ //doesn't exist. Then try to create it, but the transaction will already by aborted by then.
+ $insert_id = $this->db->GenID($this->_db_table_prefix.$group_type.'_groups_id_seq',10);
+ if ( $value === '' ) {
+ $value = $insert_id;
+ }
+
+ $this->db->BeginTrans();
+
+ // special case for root group
+ if ($parent_id == 0) {
+ // check a root group is not already defined
+ $query = 'SELECT id FROM '. $table .' WHERE parent_id=0';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_group');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+
+ if ($rs->RowCount() > 0) {
+ $this->debug_text('add_group (): A root group already exists.');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+
+ $parent_lft = 0;
+ $parent_rgt = 1;
+ } else {
+ if (empty($parent_id)) {
+ $this->debug_text("add_group (): parent id ($parent_id) is empty, this is required");
+ $this->db->RollbackTrans();
+ return FALSE;
+ }
+
+ // grab parent details from database
+ $query = 'SELECT id, lft, rgt FROM '. $table .' WHERE id='. $parent_id;
+ $row = $this->db->GetRow($query);
+
+ if (!is_array($row)) {
+ $this->debug_db('add_group');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+
+ if (empty($row)) {
+ $this->debug_text('add_group (): Parent ID: '. $parent_id .' not found.');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+
+ $parent_lft = &$row[1];
+ $parent_rgt = &$row[2];
+
+ // make room for the new group
+ $query = 'UPDATE '. $table .' SET rgt=rgt+2 WHERE rgt>='. $parent_rgt;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_group');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+
+ $query = 'UPDATE '. $table .' SET lft=lft+2 WHERE lft>'. $parent_rgt;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_group');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+ }
+
+ $query = 'INSERT INTO '. $table .' (id,parent_id,name,value,lft,rgt) VALUES ('. $insert_id .','. $parent_id .','. $this->db->quote($name) .','. $this->db->quote($value) .','. $parent_rgt .','. ($parent_rgt + 1) .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_group');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+
+ $this->db->CommitTrans();
+
+ $this->debug_text('add_group (): Added group as ID: '. $insert_id);
+ return $insert_id;
+ }
+
+ /**
+ * get_group_objects()
+ *
+ * Gets all objects assigned to a group.
+ *
+ * If $option == 'RECURSE' it will get all objects in child groups as well.
+ * defaults to omit child groups.
+ *
+ * @return array Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+
+ *
+ * @param int Group ID #
+ * @param string Group Type, either 'ARO' or 'AXO'
+ * @param string Option, either 'RECURSE' or 'NO_RECURSE'
+ */
+ function get_group_objects($group_id, $group_type='ARO', $option='NO_RECURSE') {
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $object_table = $this->_db_table_prefix .'axo';
+ $group_table = $this->_db_table_prefix .'axo_groups';
+ $map_table = $this->_db_table_prefix .'groups_axo_map';
+ break;
+ default:
+ $group_type = 'aro';
+ $object_table = $this->_db_table_prefix .'aro';
+ $group_table = $this->_db_table_prefix .'aro_groups';
+ $map_table = $this->_db_table_prefix .'groups_aro_map';
+ break;
+ }
+
+ $this->debug_text("get_group_objects(): Group ID: $group_id");
+
+ if (empty($group_id)) {
+ $this->debug_text("get_group_objects(): Group ID: ($group_id) is empty, this is required");
+ return false;
+ }
+
+ $query = '
+ SELECT o.section_value,o.value';
+
+ if ($option == 'RECURSE') {
+ $query .= '
+ FROM '. $group_table .' g2
+ JOIN '. $group_table .' g1 ON g1.lft>=g2.lft AND g1.rgt<=g2.rgt
+ JOIN '. $map_table .' gm ON gm.group_id=g1.id
+ JOIN '. $object_table .' o ON o.id=gm.'. $group_type .'_id
+ WHERE g2.id='. $group_id;
+ } else {
+ $query .= '
+ FROM '. $map_table .' gm
+ JOIN '. $object_table .' o ON o.id=gm.'. $group_type .'_id
+ WHERE gm.group_id='. $group_id;
+ }
+
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_group_objects');
+ return false;
+ }
+
+ $this->debug_text("get_group_objects(): Got group objects, formatting array.");
+
+ $retarr = array();
+
+ //format return array.
+ while ($row = $rs->FetchRow()) {
+ $section = &$row[0];
+ $value = &$row[1];
+
+ $retarr[$section][] = $value;
+ }
+
+ return $retarr;
+ }
+
+ /**
+ * add_group_object()
+ *
+ * Assigns an Object to a group
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise.
+ *
+ * @param int Group ID #
+ * @param string Object Section Value
+ * @param string Object Value
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function add_group_object($group_id, $object_section_value, $object_value, $group_type='ARO') {
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $table = $this->_db_table_prefix .'groups_axo_map';
+ $object_table = $this->_db_table_prefix .'axo';
+ $group_table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $group_type = 'aro';
+ $table = $this->_db_table_prefix .'groups_aro_map';
+ $object_table = $this->_db_table_prefix .'aro';
+ $group_table = $this->_db_table_prefix .'aro_groups';
+ break;
+ }
+
+ $this->debug_text("add_group_object(): Group ID: $group_id Section Value: $object_section_value Value: $object_value Group Type: $group_type");
+
+ $object_section_value = trim($object_section_value);
+ $object_value = trim($object_value);
+
+ if (empty($group_id) OR empty($object_value) OR empty($object_section_value)) {
+ $this->debug_text("add_group_object(): Group ID: ($group_id) OR Value ($object_value) OR Section value ($object_section_value) is empty, this is required");
+ return false;
+ }
+
+ // test to see if object & group exist and if object is already a member
+ $query = '
+ SELECT o.id AS id,g.id AS group_id,gm.group_id AS member
+ FROM '. $object_table .' o
+ LEFT JOIN '. $group_table .' g ON g.id='. $group_id .'
+ LEFT JOIN '. $table .' gm ON (gm.'. $group_type .'_id=o.id AND gm.group_id=g.id)
+ WHERE (o.section_value='. $this->db->quote($object_section_value) .' AND o.value='. $this->db->quote($object_value) .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_group_object');
+ return FALSE;
+ }
+
+ if ($rs->RecordCount() != 1) {
+ $this->debug_text('add_group_object(): Value ('. $object_value .') OR Section value ('. $object_section_value .') is invalid. Does this object exist?');
+ return FALSE;
+ }
+
+ $row = $rs->FetchRow();
+
+ if ($row[1] != $group_id) {
+ $this->debug_text('add_group_object(): Group ID ('. $group_id .') is invalid. Does this group exist?');
+ return FALSE;
+ }
+
+ //Group_ID == Member
+ if ($row[1] == $row[2]) {
+ $this->debug_text('add_group_object(): Object: ('. $object_section_value .' -> '. $object_value .') is already a member of Group: ('. $group_id .')');
+ //Object is already assigned to group. Return true.
+ return TRUE;
+ }
+
+ $object_id = $row[0];
+
+ $query = 'INSERT INTO '. $table .' (group_id,'. $group_type .'_id) VALUES ('. $group_id .','. $object_id .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_group_object');
+ return FALSE;
+ }
+
+ $this->debug_text('add_group_object(): Added Object: '. $object_id .' to Group ID: '. $group_id);
+
+ if ($this->_caching == TRUE AND $this->_force_cache_expire == TRUE) {
+ //Expire all cache.
+ $this->Cache_Lite->clean('default');
+ }
+
+ return TRUE;
+ }
+
+ /**
+ * del_group_object()
+ *
+ * Removes an Object from a group.
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise
+ *
+ * @param int Group ID #
+ * @param string Object Section Value
+ * @param string Object Value
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function del_group_object($group_id, $object_section_value, $object_value, $group_type='ARO') {
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $table = $this->_db_table_prefix .'groups_axo_map';
+ break;
+ default:
+ $group_type = 'aro';
+ $table = $this->_db_table_prefix .'groups_aro_map';
+ break;
+ }
+
+ $this->debug_text("del_group_object(): Group ID: $group_id Section value: $object_section_value Value: $object_value");
+
+ $object_section_value = trim($object_section_value);
+ $object_value = trim($object_value);
+
+ if (empty($group_id) OR empty($object_value) OR empty($object_section_value)) {
+ $this->debug_text("del_group_object(): Group ID: ($group_id) OR Section value: $object_section_value OR Value ($object_value) is empty, this is required");
+ return false;
+ }
+
+ if (!$object_id = $this->get_object_id($object_section_value, $object_value, $group_type)) {
+ $this->debug_text ("del_group_object (): Group ID ($group_id) OR Value ($object_value) OR Section value ($object_section_value) is invalid. Does this object exist?");
+ return FALSE;
+ }
+
+ $query = 'DELETE FROM '. $table .' WHERE group_id='. $group_id .' AND '. $group_type .'_id='. $object_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('del_group_object');
+ return false;
+ }
+
+ $this->debug_text("del_group_object(): Deleted Value: $object_value to Group ID: $group_id assignment");
+
+ if ($this->_caching == TRUE AND $this->_force_cache_expire == TRUE) {
+ //Expire all cache.
+ $this->Cache_Lite->clean('default');
+ }
+
+ return true;
+ }
+
+ /**
+ * edit_group()
+ *
+ * Edits a group
+ *
+ * @returns bool Returns TRUE if successful, FALSE otherwise
+ *
+ * @param int Group ID #
+ * @param string Group Value
+ * @param string Group Name
+ * @param int Parent ID #
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function edit_group($group_id, $value=NULL, $name=NULL, $parent_id=NULL, $group_type='ARO') {
+ $this->debug_text("edit_group(): ID: $group_id Name: $name Value: $value Parent ID: $parent_id Group Type: $group_type");
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $group_type = 'aro';
+ $table = $this->_db_table_prefix .'aro_groups';
+ break;
+ }
+
+ if (empty($group_id) ) {
+ $this->debug_text('edit_group(): Group ID ('. $group_id .') is empty, this is required');
+ return FALSE;
+ }
+
+ if ( !is_array($curr = $this->get_group_data($group_id, $group_type)) ) {
+ $this->debug_text('edit_group(): Invalid Group ID: '. $group_id);
+ return FALSE;
+ }
+
+ $name = trim($name);
+
+ // don't set name if it is unchanged
+ if ($name == $curr[3]) {
+ unset($name);
+ }
+
+ // don't set parent_id if it is unchanged
+ if ($parent_id == $curr[1]) {
+ unset($parent_id);
+ }
+
+ if (!empty($parent_id)) {
+ if ($group_id == $parent_id) {
+ $this->debug_text('edit_group(): Groups can\'t be a parent to themselves. Incest is bad. ;)');
+ return FALSE;
+ }
+
+ //Make sure we don't re-parent to our own children.
+ //Grab all children of this group_id.
+ $children_ids = $this->get_group_children($group_id, $group_type, 'RECURSE');
+ if (is_array($children_ids)) {
+ if (@in_array($parent_id, $children_ids) ) {
+ $this->debug_text('edit_group(): Groups can\'t be re-parented to their own children, this would be incestuous!');
+ return FALSE;
+ }
+ }
+ unset($children_ids);
+
+ // make sure parent exists
+ if (!$this->get_group_data($parent_id, $group_type)) {
+ $this->debug_text('edit_group(): Parent Group ('. $parent_id .') doesn\'t exist');
+ return FALSE;
+ }
+ }
+
+ $set = array();
+
+ // update name if it is specified.
+ if (!empty($name)) {
+ $set[] = 'name='. $this->db->quote($name);
+ }
+
+ // update parent_id if it is specified.
+ if (!empty($parent_id)) {
+ $set[] = 'parent_id='. $parent_id;
+ }
+
+ // update value if it is specified.
+ if (!empty($value)) {
+ $set[] = 'value='. $this->db->quote($value);
+ }
+
+ if (empty($set)) {
+ $this->debug_text('edit_group(): Nothing to update.');
+ return FALSE;
+ }
+
+ $this->db->BeginTrans();
+
+ $query = 'UPDATE '. $table .' SET '. implode(',', $set) .' WHERE id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('edit_group');
+ $this->db->RollbackTrans();
+ return FALSE;
+ }
+
+ $this->debug_text('edit_group(): Modified group ID: '. $group_id);
+
+ // rebuild group tree if parent_id has changed
+ if (!empty($parent_id)) {
+ if (!$this->_rebuild_tree($table, $this->get_root_group_id($group_type))) {
+ $this->db->RollbackTrans();
+ return FALSE;
+ }
+ }
+
+ $this->db->CommitTrans();
+
+ if ($this->_caching == TRUE AND $this->_force_cache_expire == TRUE) {
+ // Expire all cache.
+ $this->Cache_Lite->clean('default');
+ }
+
+ return TRUE;
+ }
+
+ /**
+ * rebuild_tree ()
+ *
+ * rebuilds the group tree for the given type
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise
+ *
+ * @param string Group Type, either 'ARO' or 'AXO'
+ * @param int Group ID #
+ * @param int Left value of Group
+ */
+ function rebuild_tree($group_type = 'ARO', $group_id = NULL, $left = 1) {
+ $this->debug_text("rebuild_tree(): Group Type: $group_type Group ID: $group_id Left: $left");
+
+ switch (strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $table = $this->_db_table_prefix .'axo_groups';
+ break;
+ default:
+ $group_type = 'aro';
+ $table = $this->_db_table_prefix .'aro_groups';
+ break;
+ }
+
+ if (!isset($group_id)) {
+ if ($group_id = $this->get_root_group_id($group_type)) {
+ $left = 1;
+ $this->debug_text('rebuild_tree(): No Group ID Specified, using Root Group ID: '. $group_id);
+ } else {
+ $this->debug_text('rebuild_tree(): A Root group could not be found, are there any groups defined?');
+ return FALSE;
+ }
+ }
+
+ $this->db->BeginTrans();
+ $rebuilt = $this->_rebuild_tree($table, $group_id, $left);
+
+ if ($rebuilt === FALSE) {
+ $this->debug_text('rebuild_tree(): Error rebuilding tree!');
+ $this->db->RollBackTrans();
+ return FALSE;
+ }
+
+ $this->db->CommitTrans();
+ $this->debug_text('rebuild_tree(): Tree rebuilt.');
+ return TRUE;
+ }
+ /**
+ * _rebuild_tree ()
+ *
+ * Utility recursive function called by rebuild_tree()
+ *
+ * @return int Returns right value of this node + 1
+ *
+ * @param string Table name of group type
+ * @param int Group ID #
+ * @param int Left value of Group
+ */
+ function _rebuild_tree($table, $group_id, $left = 1) {
+ $this->debug_text("_rebuild_tree(): Table: $table Group ID: $group_id Left: $left");
+
+ // get all children of this node
+ $query = 'SELECT id FROM '. $table .' WHERE parent_id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('_rebuild_tree');
+ return FALSE;
+ }
+
+ // the right value of this node is the left value + 1
+ $right = $left + 1;
+
+ while ($row = $rs->FetchRow()) {
+ // recursive execution of this function for each
+ // child of this node
+ // $right is the current right value, which is
+ // incremented by the rebuild_tree function
+ $right = $this->_rebuild_tree($table, $row[0], $right);
+
+ if ($right === FALSE) {
+ return FALSE;
+ }
+ }
+
+ // we've got the left value, and now that we've processed
+ // the children of this node we also know the right value
+ $query = 'UPDATE '. $table .' SET lft='. $left .', rgt='. $right .' WHERE id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('_rebuild_tree');
+ return FALSE;
+ }
+
+ // return the right value of this node + 1
+ return $right + 1;
+ }
+
+ /**
+ * del_group()
+ *
+ * deletes a given group
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise.
+ *
+ * @param int Group ID #
+ * @param bool If TRUE, child groups of this group will be reparented to the current group's parent.
+ * @param string Group Type, either 'ARO' or 'AXO'
+ */
+ function del_group($group_id, $reparent_children=TRUE, $group_type='ARO') {
+
+ switch(strtolower(trim($group_type))) {
+ case 'axo':
+ $group_type = 'axo';
+ $table = $this->_db_table_prefix .'axo_groups';
+ $groups_map_table = $this->_db_table_prefix .'axo_groups_map';
+ $groups_object_map_table = $this->_db_table_prefix .'groups_axo_map';
+ break;
+ default:
+ $group_type = 'aro';
+ $table = $this->_db_table_prefix .'aro_groups';
+ $groups_map_table = $this->_db_table_prefix .'aro_groups_map';
+ $groups_object_map_table = $this->_db_table_prefix .'groups_aro_map';
+ break;
+ }
+
+ $this->debug_text("del_group(): ID: $group_id Reparent Children: $reparent_children Group Type: $group_type");
+
+ if (empty($group_id) ) {
+ $this->debug_text("del_group(): Group ID ($group_id) is empty, this is required");
+ return false;
+ }
+
+ // Get details of this group
+ $query = 'SELECT id, parent_id, name, lft, rgt FROM '. $table .' WHERE id='. $group_id;
+ $group_details = $this->db->GetRow($query);
+
+ if (!is_array($group_details)) {
+ $this->debug_db('del_group');
+ return false;
+ }
+
+ $parent_id = $group_details[1];
+
+ $left = $group_details[3];
+ $right = $group_details[4];
+
+ $this->db->BeginTrans();
+
+ // grab list of all children
+ $children_ids = $this->get_group_children($group_id, $group_type, 'RECURSE');
+
+ // prevent deletion of root group & reparent of children if it has more than one immediate child
+ if ($parent_id == 0) {
+ $query = 'SELECT count(*) FROM '. $table .' WHERE parent_id='. $group_id;
+ $child_count = $this->db->GetOne($query);
+
+ if (($child_count > 1) AND $reparent_children) {
+ $this->debug_text ('del_group (): You cannot delete the root group and reparent children, this would create multiple root groups.');
+ $this->db->RollbackTrans();
+ return FALSE;
+ }
+ }
+
+ $success = FALSE;
+
+ /*
+ * Handle children here.
+ */
+ switch (TRUE) {
+ // there are no child groups, just delete group
+ case !is_array($children_ids):
+ case count($children_ids) == 0:
+ // remove acl maps
+ $query = 'DELETE FROM '. $groups_map_table .' WHERE group_id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // remove group object maps
+ $query = 'DELETE FROM '. $groups_object_map_table .' WHERE group_id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // remove group
+ $query = 'DELETE FROM '. $table .' WHERE id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // move all groups right of deleted group left by width of deleted group
+ $query = 'UPDATE '. $table .' SET lft=lft-'. ($right-$left+1) .' WHERE lft>'. $right;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ $query = 'UPDATE '. $table .' SET rgt=rgt-'. ($right-$left+1) .' WHERE rgt>'. $right;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ $success = TRUE;
+ break;
+ case $reparent_children == TRUE:
+ // remove acl maps
+ $query = 'DELETE FROM '. $groups_map_table .' WHERE group_id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // remove group object maps
+ $query = 'DELETE FROM '. $groups_object_map_table .' WHERE group_id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // remove group
+ $query = 'DELETE FROM '. $table .' WHERE id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // set parent of immediate children to parent group
+ $query = 'UPDATE '. $table .' SET parent_id='. $parent_id .' WHERE parent_id='. $group_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // move all children left by 1
+ $query = 'UPDATE '. $table .' SET lft=lft-1, rgt=rgt-1 WHERE lft>'. $left .' AND rgt<'. $right;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // move all groups right of deleted group left by 2
+ $query = 'UPDATE '. $table .' SET lft=lft-2 WHERE lft>'. $right;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ $query = 'UPDATE '. $table .' SET rgt=rgt-2 WHERE rgt>'. $right;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ $success = TRUE;
+ break;
+ default:
+ // make list of group and all children
+ $group_ids = $children_ids;
+ $group_ids[] = $group_id;
+
+ // remove acl maps
+ $query = 'DELETE FROM '. $groups_map_table .' WHERE group_id IN ('. implode (',', $group_ids) .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // remove group object maps
+ $query = 'DELETE FROM '. $groups_object_map_table .' WHERE group_id IN ('. implode (',', $group_ids) .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // remove groups
+ $query = 'DELETE FROM '. $table .' WHERE id IN ('. implode (',', $group_ids) .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ // move all groups right of deleted group left by width of deleted group
+ $query = 'UPDATE '. $table .' SET lft=lft-'. ($right - $left + 1) .' WHERE lft>'. $right;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ $query = 'UPDATE '. $table .' SET rgt=rgt-'. ($right - $left + 1) .' WHERE rgt>'. $right;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ break;
+ }
+
+ $success = TRUE;
+ }
+
+ // if the delete failed, rollback the trans and return false
+ if (!$success) {
+
+ $this->debug_db('del_group');
+ $this->db->RollBackTrans();
+ return false;
+ }
+
+ $this->debug_text("del_group(): deleted group ID: $group_id");
+ $this->db->CommitTrans();
+
+ if ($this->_caching == TRUE AND $this->_force_cache_expire == TRUE) {
+ //Expire all cache.
+ $this->Cache_Lite->clean('default');
+ }
+
+ return true;
+
+ }
+
+
+ /*
+ *
+ * Objects (ACO/ARO/AXO)
+ *
+ */
+
+ /**
+ * get_object()
+ *
+ * Grabs all Objects's in the database, or specific to a section_value
+ *
+ * @return ADORecordSet Returns recordset directly, with object ID only selected:
+ *
+ * @param string Filter to this section value
+ * @param int Returns hidden objects if 1, leaves them out otherwise.
+ * @param string Object Type, either 'ACO', 'ARO', 'AXO', or 'ACL'
+ */
+ function get_object($section_value = null, $return_hidden=1, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ break;
+ case 'acl':
+ $object_type = 'acl';
+ $table = $this->_db_table_prefix .'acl';
+ break;
+ default:
+ $this->debug_text('get_object(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("get_object(): Section Value: $section_value Object Type: $object_type");
+
+ $query = 'SELECT id FROM '. $table;
+
+ $where = array();
+
+ if (!empty($section_value)) {
+ $where[] = 'section_value='. $this->db->quote($section_value);
+ }
+
+ if ($return_hidden==0 AND $object_type != 'acl') {
+ $where[] = 'hidden=0';
+ }
+
+ if (!empty($where)) {
+ $query .= ' WHERE '. implode(' AND ', $where);
+ }
+
+ $rs = $this->db->GetCol($query);
+
+ if (!is_array($rs)) {
+ $this->debug_db('get_object');
+ return false;
+ }
+
+ // Return Object IDs
+ return $rs;
+ }
+ /**
+ * get_ungrouped_objects()
+ *
+ * Grabs ID's of all Objects (ARO's and AXO's only) in the database not assigned to a Group.
+ *
+ * This function is useful for applications that synchronize user databases with an outside source.
+ * If syncrhonization doesn't automatically place users in an appropriate group, this function can
+ * quickly identify them so that they can be assigned to the correct group.
+ *
+ * @return array Returns an array of object ID's
+ *
+ * @param int Returns hidden objects if 1, does not if 0.
+ * @param string Object Type, either 'ARO' or 'AXO' (groupable types)
+ */
+
+ function get_ungrouped_objects($return_hidden=1, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ break;
+ default:
+ $this->debug_text('get_ungrouped_objects(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("get_ungrouped_objects(): Object Type: $object_type");
+
+ $query = 'SELECT id FROM '. $table. ' a
+ LEFT JOIN ' . $this->_db_table_prefix. 'groups_'.$object_type.'_map b ON a.id = b.'. $object_type .'_id';
+
+ $where = array();
+ $where[] = 'b.group_id IS NULL';
+
+ if ($return_hidden==0) {
+ $where[] = 'a.hidden=0';
+ }
+
+ if (!empty($where)) {
+ $query .= ' WHERE '. implode(' AND ', $where);
+ }
+
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_ungrouped_objects');
+ return false;
+ }
+
+ while(!$rs->EOF) {
+ $retarr[] = $rs->fields[0];
+ $rs->MoveNext();
+ }
+
+ // Return Array of object IDS
+ return $retarr;
+ }
+
+
+ /**
+ * get_objects ()
+ *
+ * Grabs all Objects in the database, or specific to a section_value
+ *
+ * @return array Returns objects in format suitable for add_acl and is_conflicting_acl
+ * - i.e. Associative array, item={Section Value}, key={Array of Object Values} i.e. ["<Section Value>" => ["<Value 1>", "<Value 2>", "<Value 3>"], ...]
+ *
+ * @param string Filter for section value
+ * @param int Returns hidden objects if 1, does not if 0
+ * @param string Object Type, either 'ACO', 'ARO', 'AXO'
+ */
+ function get_objects($section_value = NULL, $return_hidden = 1, $object_type = NULL) {
+ switch (strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ break;
+ default:
+ $this->debug_text('get_objects(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("get_objects(): Section Value: $section_value Object Type: $object_type");
+
+ $query = 'SELECT section_value,value FROM '. $table;
+
+ $where = array();
+
+ if (!empty($section_value)) {
+ $where[] = 'section_value='. $this->db->quote($section_value);
+ }
+
+ if ($return_hidden==0) {
+ $where[] = 'hidden=0';
+ }
+
+ if (!empty($where)) {
+ $query .= ' WHERE '. implode(' AND ', $where);
+ }
+
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_objects');
+ return FALSE;
+ }
+
+ $retarr = array();
+
+ while ($row = $rs->FetchRow()) {
+ $retarr[$row[0]][] = $row[1];
+ }
+
+ // Return objects
+ return $retarr;
+ }
+
+ /**
+ * get_object_data()
+ *
+ * Gets all data pertaining to a specific Object.
+ *
+ * @return array Returns 2-Dimensional array of rows with columns = ( section_value, value, order_value, name, hidden )
+ *
+ * @param int Object ID #
+ * @param string Object Type, either 'ACO', 'ARO', 'AXO'
+ */
+ function get_object_data($object_id, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ break;
+ default:
+ $this->debug_text('get_object_data(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("get_object_data(): Object ID: $object_id Object Type: $object_type");
+
+ if (empty($object_id) ) {
+ $this->debug_text("get_object_data(): Object ID ($object_id) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("get_object_data(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ $query = 'SELECT section_value,value,order_value,name,hidden FROM '. $table .' WHERE id='. $object_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_object_data');
+ return false;
+ }
+
+ if ($rs->RecordCount() < 1) {
+ $this->debug_text('get_object_data(): Returned '. $row_count .' rows');
+ return FALSE;
+ }
+
+ // Return all objects
+ return $rs->GetRows();
+ }
+
+ /**
+ * get_object_id()
+ *
+ * Gets the object_id given the section_value AND value of the object.
+ *
+ * @return int Object ID #
+ *
+ * @param string Object Section Value
+ * @param string Object Value
+ * @param string Object Type, either 'ACO', 'ARO', 'AXO'
+ */
+ function get_object_id($section_value, $value, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ break;
+ default:
+ $this->debug_text('get_object_id(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("get_object_id(): Section Value: $section_value Value: $value Object Type: $object_type");
+
+ $section_value = trim($section_value);
+ $value = trim($value);
+
+ if (empty($section_value) AND empty($value) ) {
+ $this->debug_text("get_object_id(): Section Value ($value) AND value ($value) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("get_object_id(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ $query = 'SELECT id FROM '. $table .' WHERE section_value='. $this->db->quote($section_value) .' AND value='. $this->db->quote($value);
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_object_id');
+ return false;
+ }
+
+ $row_count = $rs->RecordCount();
+
+ if ($row_count > 1) {
+ $this->debug_text("get_object_id(): Returned $row_count rows, can only return one. This should never happen, the database may be missing a unique key.");
+ return false;
+ }
+
+ if ($row_count == 0) {
+ $this->debug_text("get_object_id(): Returned $row_count rows");
+ return false;
+ }
+
+ $row = $rs->FetchRow();
+
+ //Return the ID.
+ return $row[0];
+ }
+
+ /**
+ * get_object_section_value()
+ *
+ * Gets the object_section_value given object id
+ *
+ * @return string Object Section Value
+ *
+ * @param int Object ID #
+ * @param string Object Type, either 'ACO', 'ARO', or 'AXO'
+ */
+ function get_object_section_value($object_id, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ break;
+ default:
+ $this->debug_text('get_object_section_value(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("get_object_section_value(): Object ID: $object_id Object Type: $object_type");
+
+ if (empty($object_id) ) {
+ $this->debug_text("get_object_section_value(): Object ID ($object_id) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("get_object_section_value(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ $query = 'SELECT section_value FROM '. $table .' WHERE id='. $object_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_object_section_value');
+ return false;
+ }
+
+ $row_count = $rs->RecordCount();
+
+ if ($row_count > 1) {
+ $this->debug_text("get_object_section_value(): Returned $row_count rows, can only return one.");
+ return false;
+ }
+
+ if ($row_count == 0) {
+ $this->debug_text("get_object_section_value(): Returned $row_count rows");
+ return false;
+ }
+
+ $row = $rs->FetchRow();
+
+ //Return the ID.
+ return $row[0];
+ }
+
+ /**
+ * get_object_groups()
+ *
+ * Gets all groups an object is a member of.
+ *
+ * If $option == 'RECURSE' it will get all ancestor groups.
+ * defaults to only get direct parents.
+ *
+ * @return array Array of Group ID #'s, or FALSE if Failed
+ *
+ * @param int Object ID #
+ * @param string Object Type, either 'ARO' or 'AXO'
+ * @param string Option, either 'RECURSE', or 'NO_RECURSE'
+ */
+ function get_object_groups($object_id, $object_type = 'ARO', $option = 'NO_RECURSE') {
+ $this->debug_text('get_object_groups(): Object ID: '. $object_id .' Object Type: '. $object_type .' Option: '. $option);
+
+ switch(strtolower(trim($object_type))) {
+ case 'axo':
+ $object_type = 'axo';
+ $group_table = $this->_db_table_prefix .'axo_groups';
+ $map_table = $this->_db_table_prefix .'groups_axo_map';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $group_table = $this->_db_table_prefix .'aro_groups';
+ $map_table = $this->_db_table_prefix .'groups_aro_map';
+ break;
+ default:
+ $this->debug_text('get_object_groups(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ if (empty($object_id)) {
+ $this->debug_text('get_object_groups(): Object ID: ('. $object_id .') is empty, this is required');
+ return FALSE;
+ }
+
+ if (strtoupper($option) == 'RECURSE') {
+ $query = '
+ SELECT DISTINCT g.id AS group_id
+ FROM '. $map_table .' gm
+ LEFT JOIN '. $group_table .' g1 ON g1.id=gm.group_id
+ LEFT JOIN '. $group_table .' g ON g.lft<=g1.lft AND g.rgt>=g1.rgt';
+ } else {
+ $query = '
+ SELECT gm.group_id
+ FROM '. $map_table .' gm';
+ }
+
+ $query .= '
+ WHERE gm.'. $object_type .'_id='. $object_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_object_groups');
+ return FALSE;
+ }
+
+ $retarr = array();
+
+ while ($row = $rs->FetchRow()) {
+ $retarr[] = $row[0];
+ }
+
+ return $retarr;
+ }
+
+ /**
+ * add_object()
+ *
+ * Inserts a new object
+ *
+ * @return int Returns the ID # of the new object if successful, FALSE otherwise
+ *
+ * @param string Object Section Value
+ * @param string Object Name
+ * @param string Object Value
+ * @param int Display Order
+ * @param int Hidden Flag, either 1 to hide, or 0 to show.
+ * @param string Object Type, either 'ACO', 'ARO', or 'AXO'
+ */
+ function add_object($section_value, $name, $value=0, $order=0, $hidden=0, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ $object_sections_table = $this->_db_table_prefix .'aco_sections';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ $object_sections_table = $this->_db_table_prefix .'aro_sections';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ $object_sections_table = $this->_db_table_prefix .'axo_sections';
+ break;
+ default:
+ $this->debug_text('add_object(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("add_object(): Section Value: $section_value Value: $value Order: $order Name: $name Object Type: $object_type");
+
+ $section_value = trim($section_value);
+ $name = trim($name);
+ $value = trim($value);
+ $order = trim($order);
+ $hidden = intval($hidden);
+
+ if ($order == NULL OR $order == '') {
+ $order = 0;
+ }
+
+ if (empty($name) OR empty($section_value) ) {
+ $this->debug_text("add_object(): name ($name) OR section value ($section_value) is empty, this is required");
+ return false;
+ }
+
+ if (strlen($name) >= 255 OR strlen($value) >= 230 ) {
+ $this->debug_text("add_object(): name ($name) OR value ($value) is too long.");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("add_object(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ // Test to see if the section is invalid or object already exists.
+ $query = '
+ SELECT CASE WHEN o.id IS NULL THEN 0 ELSE 1 END AS object_exists
+ FROM '. $object_sections_table .' s
+ LEFT JOIN '. $table .' o ON (s.value=o.section_value AND o.value='. $this->db->quote($value) .')
+ WHERE s.value='. $this->db->quote($section_value);
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_object');
+ return FALSE;
+ }
+
+ if ($rs->RecordCount() != 1) {
+ // Section is invalid
+ $this->debug_text("add_object(): Section Value: $section_value Object Type ($object_type) does not exist, this is required");
+ return false;
+ }
+
+ $row = $rs->FetchRow();
+
+ if ($row[0] == 1) {
+ //Object is already created.
+ return true;
+ }
+
+ $insert_id = $this->db->GenID($this->_db_table_prefix.$object_type.'_seq',10);
+ $query = 'INSERT INTO '. $table .' (id,section_value,value,order_value,name,hidden) VALUES('. $insert_id .','. $this->db->quote($section_value) .','. $this->db->quote($value) .','. $order .','. $this->db->quote($name) .','. $hidden .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_object');
+ return false;
+ }
+
+ $this->debug_text("add_object(): Added object as ID: $insert_id");
+ return $insert_id;
+ }
+
+ /**
+ * edit_object()
+ *
+ * Edits a given Object
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise
+ *
+ * @param int Object ID #
+ * @param string Object Section Value
+ * @param string Object Name
+ * @param string Object Value
+ * @param int Display Order
+ * @param int Hidden Flag, either 1 to hide, or 0 to show
+ * @param string Object Type, either 'ACO', 'ARO', or 'AXO'
+ */
+ function edit_object($object_id, $section_value, $name, $value=0, $order=0, $hidden=0, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ $object_map_table = $this->_db_table_prefix .'aco_map';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ $object_map_table = $this->_db_table_prefix .'aro_map';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ $object_map_table = $this->_db_table_prefix .'axo_map';
+ break;
+ }
+
+ $this->debug_text("edit_object(): ID: $object_id Section Value: $section_value Value: $value Order: $order Name: $name Object Type: $object_type");
+
+ $section_value = trim($section_value);
+ $name = trim($name);
+ $value = trim($value);
+ $order = trim($order);
+ $hidden = intval($hidden);
+
+ if (empty($object_id) OR empty($section_value) ) {
+ $this->debug_text("edit_object(): Object ID ($object_id) OR Section Value ($section_value) is empty, this is required");
+ return false;
+ }
+
+ if (empty($name) ) {
+ $this->debug_text("edit_object(): name ($name) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("edit_object(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ $this->db->BeginTrans();
+
+ //Get old value incase it changed, before we do the update.
+ $query = 'SELECT value, section_value FROM '. $table .' WHERE id='. $object_id;
+ $old = $this->db->GetRow($query);
+
+ $query = '
+ UPDATE '. $table .'
+ SET section_value='. $this->db->quote($section_value) .',
+ value='. $this->db->quote($value) .',
+ order_value='. $this->db->quote($order) .',
+ name='. $this->db->quote($name) .',
+ hidden='. $hidden .'
+ WHERE id='. $object_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('edit_object');
+ $this->db->RollbackTrans();
+ return false;
+ }
+
+ $this->debug_text('edit_object(): Modified '. strtoupper($object_type) .' ID: '. $object_id);
+
+ if ($old[0] != $value OR $old[1] != $section_value) {
+ $this->debug_text("edit_object(): Value OR Section Value Changed, update other tables.");
+
+ $query = '
+ UPDATE '. $object_map_table .'
+ SET value='. $this->db->quote($value) .',
+ section_value='. $this->db->quote($section_value) .'
+ WHERE section_value='. $this->db->quote($old[1]) .'
+ AND value='. $this->db->quote($old[0]);
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('edit_object');
+ $this->db->RollbackTrans();
+ return FALSE;
+ }
+
+ $this->debug_text ('edit_object(): Modified Map Value: '. $value .' Section Value: '. $section_value);
+ }
+
+ $this->db->CommitTrans();
+
+ return TRUE;
+ }
+
+ /**
+ * del_object()
+ *
+ * Deletes a given Object and, if instructed to do so, erase all referencing objects
+ *
+ * ERASE feature by: Martino Piccinato
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise.
+ *
+ * @param int Object ID #
+ * @param string Object Type, either 'ACO', 'ARO', or 'AXO'
+ * @param bool Erases all referencing objects if TRUE, leaves them alone otherwise.
+ */
+ function del_object($object_id, $object_type=NULL, $erase=FALSE) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ $object_map_table = $this->_db_table_prefix .'aco_map';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ $object_map_table = $this->_db_table_prefix .'aro_map';
+ $groups_map_table = $this->_db_table_prefix .'aro_groups_map';
+ $object_group_table = $this->_db_table_prefix .'groups_aro_map';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ $object_map_table = $this->_db_table_prefix .'axo_map';
+ $groups_map_table = $this->_db_table_prefix .'axo_groups_map';
+ $object_group_table = $this->_db_table_prefix .'groups_axo_map';
+ break;
+ default:
+ $this->debug_text('del_object(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("del_object(): ID: $object_id Object Type: $object_type, Erase all referencing objects: $erase");
+
+ if (empty($object_id) ) {
+ $this->debug_text("del_object(): Object ID ($object_id) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("del_object(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ $this->db->BeginTrans();
+
+ // Get Object section_value/value (needed to look for referencing objects)
+ $query = 'SELECT section_value,value FROM '. $table .' WHERE id='. $object_id;
+ $object = $this->db->GetRow($query);
+
+ if (empty($object)) {
+ $this->debug_text('del_object(): The specified object ('. strtoupper($object_type) .' ID: '. $object_id .') could not be found.');
+ $this->db->RollbackTrans();
+ return FALSE;
+ }
+
+ $section_value = $object[0];
+ $value = $object[1];
+
+ // Get ids of acl referencing the Object (if any)
+ $query = "SELECT acl_id FROM $object_map_table WHERE value='$value' AND section_value='$section_value'";
+ $acl_ids = $this->db->GetCol($query);
+
+ if ($erase) {
+ // We were asked to erase all acl referencing it
+
+ $this->debug_text("del_object(): Erase was set to TRUE, delete all referencing objects");
+
+ if ($object_type == "aro" OR $object_type == "axo") {
+ // The object can be referenced in groups_X_map tables
+ // in the future this branching may become useless because
+ // ACO might me "groupable" too
+
+ // Get rid of groups_map referencing the Object
+ $query = 'DELETE FROM '. $object_group_table .' WHERE '. $object_type .'_id='. $object_id;
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('edit_object');
+ $this->db->RollBackTrans();
+ return false;
+ }
+ }
+
+ if (!empty($acl_ids)) {
+ //There are acls actually referencing the object
+
+ if ($object_type == 'aco') {
+ // I know it's extremely dangerous but
+ // if asked to really erase an ACO
+ // we should delete all acl referencing it
+ // (and relative maps)
+
+ // Do this below this branching
+ // where it uses $orphan_acl_ids as
+ // the array of the "orphaned" acl
+ // in this case all referenced acl are
+ // orhpaned acl
+
+ $orphan_acl_ids = $acl_ids;
+ } else {
+ // The object is not an ACO and might be referenced
+ // in still valid acls regarding also other object.
+ // In these cases the acl MUST NOT be deleted
+
+ // Get rid of $object_id map referencing erased objects
+ $query = "DELETE FROM $object_map_table WHERE section_value='$section_value' AND value='$value'";
+ $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('edit_object');
+ $this->db->RollBackTrans();
+ return false;
+ }
+
+ // Find the "orphaned" acl. I mean acl referencing the erased Object (map)
+ // not referenced anymore by other objects
+
+ $sql_acl_ids = implode(",", $acl_ids);
+
+ $query = '
+ SELECT a.id
+ FROM '. $this->_db_table_prefix .'acl a
+ LEFT JOIN '. $object_map_table .' b ON a.id=b.acl_id
+ LEFT JOIN '. $groups_map_table .' c ON a.id=c.acl_id
+ WHERE b.value IS NULL
+ AND b.section_value IS NULL
+ AND c.group_id IS NULL
+ AND a.id in ('. $sql_acl_ids .')';
+ $orphan_acl_ids = $this->db->GetCol($query);
+
+ } // End of else section of "if ($object_type == "aco")"
+
+ if ($orphan_acl_ids) {
+ // If there are orphaned acls get rid of them
+
+ foreach ($orphan_acl_ids as $acl) {
+ $this->del_acl($acl);
+ }
+ }
+
+ } // End of if ($acl_ids)
+
+ // Finally delete the Object itself
+ $query = "DELETE FROM $table WHERE id='$object_id'";
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('edit_object');
+ $this->db->RollBackTrans();
+ return false;
+ }
+
+ $this->db->CommitTrans();
+ return true;
+
+ } // End of "if ($erase)"
+
+ $groups_ids = FALSE;
+
+ if ($object_type == 'axo' OR $object_type == 'aro') {
+ // If the object is "groupable" (may become unnecessary,
+ // see above
+
+ // Get id of groups where the object is assigned:
+ // you must explicitly remove the object from its groups before
+ // deleting it (don't know if this is really needed, anyway it's safer ;-)
+
+ $query = 'SELECT group_id FROM '. $object_group_table .' WHERE '. $object_type .'_id='. $object_id;
+ $groups_ids = $this->db->GetCol($query);
+ }
+
+ if ( ( isset($acl_ids) AND !empty($acl_ids) ) OR ( isset($groups_ids) AND !empty($groups_ids) ) ) {
+ // The Object is referenced somewhere (group or acl), can't delete it
+
+ $this->debug_text("del_object(): Can't delete the object as it is being referenced by GROUPs (".@implode($groups_ids).") or ACLs (".@implode($acl_ids,",").")");
+ $this->db->RollBackTrans();
+ return false;
+ } else {
+ // The Object is NOT referenced anywhere, delete it
+
+ $query = "DELETE FROM $table WHERE id='$object_id'";
+ $rs = $this->db->Execute($query);
+
+ if ( !is_object($rs) ) {
+ $this->debug_db('edit_object');
+ $this->db->RollBackTrans();
+ return false;
+ }
+
+ $this->db->CommitTrans();
+ return true;
+ }
+
+ $this->db->RollbackTrans();
+ return false;
+ }
+
+ /*
+ *
+ * Object Sections
+ *
+ */
+
+ /**
+ * get_object_section_section_id()
+ *
+ * Gets the object_section_id given the name AND/OR value of the section.
+ *
+ * Will only return one section id, so if there are duplicate names it will return false.
+ *
+ * @return int Object Section ID if the object section is found AND is unique, or FALSE otherwise.
+ *
+ * @param string Object Name
+ * @param string Object Value
+ * @param string Object Type, either 'ACO', 'ARO', 'AXO', or 'ACL'
+ *
+ */
+ function get_object_section_section_id($name = NULL, $value = NULL, $object_type = NULL) {
+ $this->debug_text("get_object_section_section_id(): Value: $value Name: $name Object Type: $object_type");
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ case 'aro':
+ case 'axo':
+ case 'acl':
+ $object_type = strtolower(trim($object_type));
+ $table = $this->_db_table_prefix . $object_type;
+ $object_sections_table = $this->_db_table_prefix . $object_type .'_sections';
+ break;
+ default:
+ $this->debug_text('get_object_section_section_id(): Invalid Object Type ('. $object_type . ')');
+ return FALSE;
+ }
+
+ $name = trim($name);
+ $value = trim($value);
+
+ if (empty($name) AND empty($value) ) {
+ $this->debug_text('get_object_section_section_id(): Both Name ('. $name .') and Value ('. $value .') are empty, you must specify at least one.');
+ return FALSE;
+ }
+
+ $query = 'SELECT id FROM '. $object_sections_table;
+ $where = ' WHERE ';
+
+ // limit by value if specified
+ if (!empty($value)) {
+ $query .= $where .'value='. $this->db->quote($value);
+ $where = ' AND ';
+ }
+
+ // only use name if asked, this is SLOW
+ if (!empty($name)) {
+ $query .= $where .'name='. $this->db->quote($name);
+ }
+
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('get_object_section_section_id');
+ return FALSE;
+ }
+
+ $row_count = $rs->RecordCount();
+
+ // If only one row is returned
+ if ($row_count == 1) {
+ // Return only the ID in the first row.
+ $row = $rs->FetchRow();
+ return $row[0];
+ }
+
+ // If more than one row is returned
+ // should only ever occur when using name as values are unique.
+ if ($row_count > 1) {
+ $this->debug_text('get_object_section_section_id(): Returned '. $row_count .' rows, can only return one. Please search by value not name, or make your names unique.');
+ return FALSE;
+ }
+
+ // No rows returned, no matching section found
+ $this->debug_text('get_object_section_section_id(): Returned '. $row_count .' rows, no matching section found.');
+ return FALSE;
+ }
+
+ /**
+ * add_object_section()
+ *
+ * Inserts an object Section
+ *
+ * @return int Object Section ID of new section
+ *
+ * @param string Object Name
+ * @param string Object Value
+ * @param int Display Order
+ * @param int Hidden flag, hides section if 1, shows section if 0
+ * @param string Object Type, either 'ACO', 'ARO', 'AXO', or 'ACL'
+ */
+ function add_object_section($name, $value=0, $order=0, $hidden=0, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $object_sections_table = $this->_db_table_prefix .'aco_sections';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $object_sections_table = $this->_db_table_prefix .'aro_sections';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $object_sections_table = $this->_db_table_prefix .'axo_sections';
+ break;
+ case 'acl':
+ $object_type = 'acl';
+ $object_sections_table = $this->_db_table_prefix .'acl_sections';
+ break;
+ }
+
+ $this->debug_text("add_object_section(): Value: $value Order: $order Name: $name Object Type: $object_type");
+
+ $name = trim($name);
+ $value = trim($value);
+ $order = trim($order);
+ $hidden = intval($hidden);
+
+ if ($order == NULL OR $order == '') {
+ $order = 0;
+ }
+
+ if (empty($name) ) {
+ $this->debug_text("add_object_section(): name ($name) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("add_object_section(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ $insert_id = $this->db->GenID($this->_db_table_prefix.$object_type.'_sections_seq',10);
+ $query = 'insert into '. $object_sections_table .' (id,value,order_value,name,hidden) VALUES( '. $insert_id .', '. $this->db->quote($value) .', '. $order .', '. $this->db->quote($name) .', '. $hidden .')';
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('add_object_section');
+ return false;
+ } else {
+ $this->debug_text("add_object_section(): Added object_section as ID: $insert_id");
+ return $insert_id;
+ }
+ }
+
+ /**
+ * edit_object_section()
+ *
+ * Edits a given Object Section
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise
+ *
+ * @param int Object Section ID #
+ * @param string Object Section Name
+ * @param string Object Section Value
+ * @param int Display Order
+ * @param int Hidden Flag, hide object section if 1, show if 0
+ * @param string Object Type, either 'ACO', 'ARO', 'AXO', or 'ACL'
+ */
+ function edit_object_section($object_section_id, $name, $value=0, $order=0, $hidden=0, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco';
+ $object_sections_table = $this->_db_table_prefix .'aco_sections';
+ $object_map_table = $this->_db_table_prefix .'aco_map';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro';
+ $object_sections_table = $this->_db_table_prefix .'aro_sections';
+ $object_map_table = $this->_db_table_prefix .'aro_map';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo';
+ $object_sections_table = $this->_db_table_prefix .'axo_sections';
+ $object_map_table = $this->_db_table_prefix .'axo_map';
+ break;
+ case 'acl':
+ $object_type = 'acl';
+ $table = $this->_db_table_prefix .'acl';
+ $object_sections_table = $this->_db_table_prefix .'acl_sections';
+ break;
+ default:
+ $this->debug_text('edit_object_section(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("edit_object_section(): ID: $object_section_id Value: $value Order: $order Name: $name Object Type: $object_type");
+
+ $name = trim($name);
+ $value = trim($value);
+ $order = trim($order);
+ $hidden = intval($hidden);
+
+ if (empty($object_section_id) ) {
+ $this->debug_text("edit_object_section(): Section ID ($object_section_id) is empty, this is required");
+ return false;
+ }
+
+ if (empty($name) ) {
+ $this->debug_text("edit_object_section(): name ($name) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("edit_object_section(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ $this->db->BeginTrans();
+
+ //Get old value incase it changed, before we do the update.
+ $query = "select value from $object_sections_table where id=$object_section_id";
+ $old_value = $this->db->GetOne($query);
+
+ $query = "update $object_sections_table set
+ value='$value',
+ order_value='$order',
+ name='$name',
+ hidden=$hidden
+ where id=$object_section_id";
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('edit_object_section');
+
+ $this->db->RollbackTrans();
+
+ return false;
+ } else {
+ $this->debug_text("edit_object_section(): Modified aco_section ID: $object_section_id");
+
+ if ($old_value != $value) {
+ $this->debug_text("edit_object_section(): Value Changed, update other tables.");
+
+ $query = "update $table set
+ section_value='$value'
+ where section_value = '$old_value'";
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('edit_object_section');
+
+ $this->db->RollbackTrans();
+
+ return false;
+ } else {
+ if (!empty($object_map_table)) {
+ $query = "update $object_map_table set
+ section_value='$value'
+ where section_value = '$old_value'";
+ $rs = $this->db->Execute($query);
+
+ if ( !is_object($rs) ) {
+ $this->debug_db('edit_object_section');
+
+ $this->db->RollbackTrans();
+
+ return false;
+ } else {
+ $this->debug_text("edit_object_section(): Modified ojbect_map value: $value");
+
+ $this->db->CommitTrans();
+ return true;
+ }
+ } else {
+ //ACL sections, have no mapping table. Return true.
+
+ $this->db->CommitTrans();
+
+ return true;
+ }
+ }
+ }
+
+ $this->db->CommitTrans();
+ return true;
+ }
+ }
+
+ /**
+ * del_object_section()
+ *
+ * Deletes a given Object Section and, if explicitly asked, all the section objects
+ *
+ * ERASE feature by: Martino Piccinato
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise
+ *
+ * @param int Object Section ID # to delete
+ * @param string Object Type, either 'ACO', 'ARO', 'AXO', or 'ACL'
+ * @param bool Erases all section objects assigned to the section
+ */
+ function del_object_section($object_section_id, $object_type=NULL, $erase=FALSE) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $object_sections_table = $this->_db_table_prefix .'aco_sections';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $object_sections_table = $this->_db_table_prefix .'aro_sections';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $object_sections_table = $this->_db_table_prefix .'axo_sections';
+ break;
+ case 'acl':
+ $object_type = 'acl';
+ $object_sections_table = $this->_db_table_prefix .'acl_sections';
+ break;
+ }
+
+ $this->debug_text("del_object_section(): ID: $object_section_id Object Type: $object_type, Erase all: $erase");
+
+ if (empty($object_section_id) ) {
+ $this->debug_text("del_object_section(): Section ID ($object_section_id) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("del_object_section(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ // Get the value of the section
+ $query="SELECT value FROM $object_sections_table WHERE id='$object_section_id'";
+ $section_value = $this->db->GetOne($query);
+
+ // Get all objects ids in the section
+ $object_ids = $this->get_object($section_value, 1, $object_type);
+
+ if($erase) {
+ // Delete all objects in the section and for
+ // each object delete the referencing object
+ // (see del_object method)
+ if (is_array($object_ids)) {
+ foreach ($object_ids as $id) {
+ if ( $object_type === 'acl' ) {
+ $this->del_acl($id);
+ } else {
+ $this->del_object($id, $object_type, TRUE);
+ }
+ }
+ }
+ }
+
+ if($object_ids AND !$erase) {
+ // There are objects in the section and we
+ // were not asked to erase them: don't delete it
+
+ $this->debug_text("del_object_section(): Could not delete the section ($section_value) as it is not empty.");
+
+ return false;
+
+ } else {
+ // The section is empty (or emptied by this method)
+
+ $query = "DELETE FROM $object_sections_table where id='$object_section_id'";
+ $rs = $this->db->Execute($query);
+
+ if (!is_object($rs)) {
+ $this->debug_db('del_object_section');
+ return false;
+ } else {
+ $this->debug_text("del_object_section(): deleted section ID: $object_section_id Value: $section_value");
+ return true;
+ }
+
+ }
+
+ return false;
+ }
+
+ /**
+ * get_section_data()
+ *
+ * Gets the section data given the Section Value
+ *
+ * @return array Returns numerically indexed array with the following columns:
+ * - array[0] = (int) Section ID #
+ * - array[1] = (string) Section Value
+ * - array[2] = (int) Section Order
+ * - array[3] = (string) Section Name
+ * - array[4] = (int) Section Hidden?
+ * @param string Section Value
+ * @param string Object Type, either 'ACO', 'ARO', or 'AXO'
+ */
+ function get_section_data($section_value, $object_type=NULL) {
+
+ switch(strtolower(trim($object_type))) {
+ case 'aco':
+ $object_type = 'aco';
+ $table = $this->_db_table_prefix .'aco_sections';
+ break;
+ case 'aro':
+ $object_type = 'aro';
+ $table = $this->_db_table_prefix .'aro_sections';
+ break;
+ case 'axo':
+ $object_type = 'axo';
+ $table = $this->_db_table_prefix .'axo_sections';
+ break;
+ default:
+ $this->debug_text('get_section_data(): Invalid Object Type: '. $object_type);
+ return FALSE;
+ }
+
+ $this->debug_text("get_section_data(): Section Value: $section_value Object Type: $object_type");
+
+ if (empty($section_value) ) {
+ $this->debug_text("get_section_data(): Section Value ($section_value) is empty, this is required");
+ return false;
+ }
+
+ if (empty($object_type) ) {
+ $this->debug_text("get_section_data(): Object Type ($object_type) is empty, this is required");
+ return false;
+ }
+
+ $query = "SELECT id, value, order_value, name, hidden FROM '. $table .' WHERE value='$section_value'";
+ $row = $this->db->GetRow($query);
+
+ if ($row) {
+ return $row;
+ }
+
+ $this->debug_text("get_section_data(): Section does not exist.");
+ return false;
+ }
+
+ /**
+ * clear_database()
+ *
+ * Deletes all data from the phpGACL tables. USE WITH CAUTION.
+ *
+ * @return bool Returns TRUE if successful, FALSE otherwise
+ *
+ */
+ function clear_database(){
+
+ $tablesToClear = array(
+ $this->_db_table_prefix.'acl',
+ $this->_db_table_prefix.'aco',
+ $this->_db_table_prefix.'aco_map',
+ $this->_db_table_prefix.'aco_sections',
+ $this->_db_table_prefix.'aro',
+ $this->_db_table_prefix.'aro_groups',
+ $this->_db_table_prefix.'aro_groups_map',
+ $this->_db_table_prefix.'aro_map',
+ $this->_db_table_prefix.'aro_sections',
+ $this->_db_table_prefix.'axo',
+ $this->_db_table_prefix.'axo_groups',
+ $this->_db_table_prefix.'axo_groups_map',
+ $this->_db_table_prefix.'axo_map',
+ $this->_db_table_prefix.'axo_sections',
+ $this->_db_table_prefix.'groups_aro_map',
+ $this->_db_table_prefix.'groups_axo_map'
+ );
+
+ // Get all the table names and loop
+ $tableNames = $this->db->MetaTables('TABLES');
+ $query = array();
+ foreach ($tableNames as $key => $value){
+ if (in_array($value, $tablesToClear) ) {
+ $query[] = 'TRUNCATE TABLE '.$value.';';
+ }
+ }
+
+ // Loop the queries and return.
+ foreach ($query as $key => $value){
+ $result = $this->db->Execute($value);
+ }
+
+ return TRUE;
+ }
+
+}
+?>
diff --git a/scire/user.php b/scire/user.php
index 3088029..154caec 100755
--- a/scire/user.php
+++ b/scire/user.php
@@ -19,14 +19,18 @@ if ($_POST['addgroup_confirm']) {
$userdata = $acl->get_object_data($_POST['userid'], 'ARO');
$newgroups = $_POST['addgroupid'];
#remove first.
- foreach ($ingroups as $ingroup) {
- if (!in_array($ingroup, $newgroups)) {
- $acl->del_group_object($ingroup, $userdata[0][0], $userdata[0][1], 'ARO');
+ if ($ingroups) {
+ foreach ($ingroups as $ingroup) {
+ if (!in_array($ingroup, $newgroups)) {
+ $acl->del_group_object($ingroup, $userdata[0][0], $userdata[0][1], 'ARO');
+ }
}
}
- foreach ($newgroups as $newgroup) {
- print "newgroup: $newgroup";
- $acl->add_group_object($newgroup, $userdata[0][0], $userdata[0][1], 'ARO');
+ if ($newgroups) {
+ foreach ($newgroups as $newgroup) {
+ print "newgroup: $newgroup";
+ $acl->add_group_object($newgroup, $userdata[0][0], $userdata[0][1], 'ARO');
+ }
}
$_GET['Action'] = "edit";
$_GET['userid'] = $_POST['userid'];