PluginProbe
User Access Manager / 1.2.6.7
User Access Manager v1.2.6.7
2.3.20 2.3.19 2.3.18 2.3.17 2.3.16 2.3.15 2.3.14 2.3.13 trunk 0.6 0.6.1 0.6.2 0.7 0.7 Beta 0.7.0.1 0.8 0.8.0.1 0.8.0.2 0.9 0.9.1 0.9.1.1 0.9.1.2 0.9.1.3 0.9.1.4 1.0 All 136 releases
user-access-manager / class / UserAccessManager.class.php

UserAccessManager.class.php in User Access Manager 1.2.6.7, at class/UserAccessManager.class.php

2,347 lines 69.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * UserAccessManager.class.php
4 *
5 * The UserAccessManager class file.
6 *
7 * PHP versions 5
8 *
9 * @category UserAccessManager
10 * @package UserAccessManager
11 * @author Alexander Schneider <alexanderschneider85@googlemail.com>
12 * @copyright 2008-2013 Alexander Schneider
13 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2
14 * @version SVN: $Id$
15 * @link http://wordpress.org/extend/plugins/user-access-manager/
16 */
17
18 /**
19 * The user user access manager class.
20 *
21 * @category UserAccessManager
22 * @package UserAccessManager
23 * @author Alexander Schneider <alexanderschneider85@gmail.com>
24 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2
25 * @link http://wordpress.org/extend/plugins/user-access-manager/
26 */
27 class UserAccessManager
28 {
29 protected $_blAtAdminPanel = false;
30 protected $_sAdminOptionsName = "uamAdminOptions";
31 protected $_sUamVersion = "1.2.6.7";
32 protected $_sUamDbVersion = "1.3";
33 protected $_aAdminOptions = null;
34 protected $_oAccessHandler = null;
35 protected $_aPostUrls = array();
36 protected $_aMimeTypes = null;
37 protected $_aCache = array();
38 protected $_aPosts = array();
39 protected $_aCategories = array();
40 protected $_aWpOptions = array();
41
42 /**
43 * Constructor.
44 */
45 public function __construct()
46 {
47 do_action('uam_init', $this);
48 }
49
50 /**
51 * Returns the admin options name for the uam.
52 *
53 * @return string
54 */
55 public function getAdminOptionsName()
56 {
57 return $this->_sAdminOptionsName;
58 }
59
60 /**
61 * Flushes the cache.
62 */
63 public function flushCache()
64 {
65 $this->_aCache = array();
66 }
67
68 /**
69 * Adds the variable to the cache.
70 *
71 * @param string $sKey The cache key
72 * @param mixed $mValue The value.
73 */
74 public function addToCache($sKey, $mValue)
75 {
76 $this->_aCache[$sKey] = $mValue;
77 }
78
79 /**
80 * Returns a value from the cache by the given key.
81 *
82 * @param string $sKey
83 *
84 * @return mixed
85 */
86 public function getFromCache($sKey)
87 {
88 if (isset($this->_aCache[$sKey])) {
89 return $this->_aCache[$sKey];
90 }
91
92 return null;
93 }
94
95 public function getWpOption($sOption)
96 {
97 if (!isset($this->_aWpOptions[$sOption])) {
98 $this->_aWpOptions[$sOption] = get_option($sOption);
99 }
100
101 return $this->_aWpOptions[$sOption];
102 }
103
104 /**
105 * Returns a post.
106 *
107 * @param string $sId The post id.
108 *
109 * @return mixed
110 */
111 public function getPost($sId)
112 {
113 if (!isset($this->_aPosts[$sId])) {
114 $this->_aPosts[$sId] = get_post($sId);
115 }
116
117 return $this->_aPosts[$sId];
118 }
119
120 /**
121 * Returns a category.
122 *
123 * @param string $sId The category id.
124 *
125 * @return mixed
126 */
127 public function getCategory($sId)
128 {
129 if (!isset($this->_aCategories[$sId])) {
130 $this->_aCategories[$sId] = get_category($sId);
131 }
132
133 return $this->_aCategories[$sId];
134 }
135
136 /**
137 * Returns all blog of the network.
138 *
139 * @return array()
140 */
141 protected function _getBlogIds()
142 {
143 /**
144 * @var wpdb $wpdb
145 */
146 global $wpdb;
147 $aBlogIds = array();
148
149 if (is_multisite()) {
150 $aBlogIds = $wpdb->get_col(
151 "SELECT blog_id
152 FROM ".$wpdb->blogs
153 );
154 }
155
156 return $aBlogIds;
157 }
158
159 /**
160 * Installs the user access manager.
161 *
162 * @return null;
163 */
164 public function install()
165 {
166 global $wpdb;
167 $aBlogIds = $this->_getBlogIds();
168
169 if (isset($_GET['networkwide'])
170 && ($_GET['networkwide'] == 1)
171 ) {
172 $iCurrentBlogId = $wpdb->blogid;
173
174 foreach ($aBlogIds as $iBlogId) {
175 switch_to_blog($iBlogId);
176 $this->_installUam();
177 }
178
179 switch_to_blog($iCurrentBlogId);
180
181 return null;
182 }
183
184 $this->_installUam();
185 }
186
187 /**
188 * Creates the needed tables at the database and adds the options
189 *
190 * @return null;
191 */
192 protected function _installUam()
193 {
194 /**
195 * @var wpdb $wpdb
196 */
197 global $wpdb;
198 include_once ABSPATH.'wp-admin/includes/upgrade.php';
199
200 $sCharsetCollate = $this->_getCharset();
201
202 $sDbAccessGroupTable = $wpdb->prefix.'uam_accessgroups';
203
204 $sDbUserGroup = $wpdb->get_var(
205 "SHOW TABLES
206 LIKE '".$sDbAccessGroupTable."'"
207 );
208
209 if ($sDbUserGroup != $sDbAccessGroupTable) {
210 dbDelta(
211 "CREATE TABLE ".$sDbAccessGroupTable." (
212 ID int(11) NOT NULL auto_increment,
213 groupname tinytext NOT NULL,
214 groupdesc text NOT NULL,
215 read_access tinytext NOT NULL,
216 write_access tinytext NOT NULL,
217 ip_range mediumtext NULL,
218 PRIMARY KEY (ID)
219 ) $sCharsetCollate;"
220 );
221 }
222
223 $sDbAccessGroupToObjectTable = $wpdb->prefix.'uam_accessgroup_to_object';
224
225 $sDbAccessGroupToObject = $wpdb->get_var(
226 "SHOW TABLES
227 LIKE '".$sDbAccessGroupToObjectTable."'"
228 );
229
230 if ($sDbAccessGroupToObject != $sDbAccessGroupToObjectTable) {
231 dbDelta(
232 "CREATE TABLE " . $sDbAccessGroupToObjectTable . " (
233 object_id VARCHAR(64) NOT NULL,
234 object_type varchar(64) NOT NULL,
235 group_id int(11) NOT NULL,
236 PRIMARY KEY (object_id,object_type,group_id)
237 ) $sCharsetCollate;"
238 );
239 }
240
241 add_option("uam_db_version", $this->_sUamDbVersion);
242 }
243
244 /**
245 * Checks if a database update is necessary.
246 *
247 * @return boolean
248 */
249 public function isDatabaseUpdateNecessary()
250 {
251 global $wpdb;
252 $sBlogIds = $this->_getBlogIds();
253
254 if ($sBlogIds !== array()
255 && is_super_admin()
256 ) {
257 $iCurrentBlogId = $wpdb->blogid;
258
259 foreach ($sBlogIds as $iBlogId) {
260 switch_to_blog($iBlogId);
261 $sCurrentDbVersion = $this->getWpOption("uam_db_version");
262
263 if (version_compare($sCurrentDbVersion, $this->_sUamDbVersion, '<')) {
264 switch_to_blog($iCurrentBlogId);
265 return true;
266 }
267 }
268
269 switch_to_blog($iCurrentBlogId);
270 }
271
272 $sCurrentDbVersion = $this->getWpOption("uam_db_version");
273 return version_compare($sCurrentDbVersion, $this->_sUamDbVersion, '<');
274 }
275
276 /**
277 * Updates the user access manager if an old version was installed.
278 *
279 * @param boolean $blNetworkWide If true update network wide
280 *
281 * @return null;
282 */
283 public function update($blNetworkWide)
284 {
285 global $wpdb;
286 $aBlogIds = $this->_getBlogIds();
287
288 if ($blNetworkWide
289 && $aBlogIds !== array()
290 ) {
291 $iCurrentBlogId = $wpdb->blogid;
292
293 foreach ($aBlogIds as $iBlogId) {
294 switch_to_blog($iBlogId);
295 $this->_installUam();
296 $this->_updateUam();
297 }
298
299 switch_to_blog($iCurrentBlogId);
300 } else {
301 $this->_updateUam();
302 }
303 }
304
305 /**
306 * Updates the user access manager if an old version was installed.
307 *
308 * @return null;
309 */
310 protected function _updateUam()
311 {
312 /**
313 * @var wpdb $wpdb
314 */
315 global $wpdb;
316 $sCurrentDbVersion = $this->getWpOption("uam_db_version");
317
318 if (empty($sCurrentDbVersion)) {
319 $this->install();
320 }
321
322 if (!$this->getWpOption('uam_version') || version_compare($this->getWpOption('uam_version'), "1.0", '<')) {
323 delete_option('allow_comments_locked');
324 }
325
326 $sDbAccessGroup = $wpdb->prefix.'uam_accessgroups';
327
328 $sDbUserGroup = $wpdb->get_var(
329 "SHOW TABLES
330 LIKE '".$sDbAccessGroup."'"
331 );
332
333 if (version_compare($sCurrentDbVersion, $this->_sUamDbVersion, '<')) {
334 $sCharsetCollate = $this->_getCharset();
335
336 if (version_compare($sCurrentDbVersion, "1.0", '<=')) {
337 if ($sDbUserGroup == $sDbAccessGroup) {
338 $wpdb->query(
339 "ALTER TABLE ".$sDbAccessGroup."
340 ADD read_access TINYTEXT NOT NULL DEFAULT '',
341 ADD write_access TINYTEXT NOT NULL DEFAULT '',
342 ADD ip_range MEDIUMTEXT NULL DEFAULT ''"
343 );
344
345 $wpdb->query(
346 "UPDATE ".$sDbAccessGroup."
347 SET read_access = 'group',
348 write_access = 'group'"
349 );
350
351 $sDbIpRange = $wpdb->get_var(
352 "SHOW columns
353 FROM ".$sDbAccessGroup."
354 LIKE 'ip_range'"
355 );
356
357 if ($sDbIpRange != 'ip_range') {
358 $wpdb->query(
359 "ALTER TABLE ".$sDbAccessGroup."
360 ADD ip_range MEDIUMTEXT NULL DEFAULT ''"
361 );
362 }
363 }
364
365 $sDbAccessGroupToObject = $wpdb->prefix.'uam_accessgroup_to_object';
366 $sDbAccessGroupToPost = $wpdb->prefix.'uam_accessgroup_to_post';
367 $sDbAccessGroupToUser = $wpdb->prefix.'uam_accessgroup_to_user';
368 $sDbAccessGroupToCategory = $wpdb->prefix.'uam_accessgroup_to_category';
369 $sDbAccessGroupToRole = $wpdb->prefix.'uam_accessgroup_to_role';
370
371 $wpdb->query(
372 "ALTER TABLE '{$sDbAccessGroupToObject}'
373 CHANGE 'object_id' 'object_id' VARCHAR(64)
374 ".$sCharsetCollate
375 );
376
377 $aObjectTypes = $this->getAccessHandler()->getObjectTypes();
378
379 foreach ($aObjectTypes as $sObjectType) {
380 $sAddition = '';
381
382 if ($this->getAccessHandler()->isPostableType($sObjectType)) {
383 $sDbIdName = 'post_id';
384 $sDatabase = $sDbAccessGroupToPost.', '.$wpdb->posts;
385 $sAddition = " WHERE post_id = ID
386 AND post_type = '".$sObjectType."'";
387 } elseif ($sObjectType == 'category') {
388 $sDbIdName = 'category_id';
389 $sDatabase = $sDbAccessGroupToCategory;
390 } elseif ($sObjectType == 'user') {
391 $sDbIdName = 'user_id';
392 $sDatabase = $sDbAccessGroupToUser;
393 } elseif ($sObjectType == 'role') {
394 $sDbIdName = 'role_name';
395 $sDatabase = $sDbAccessGroupToRole;
396 } else {
397 continue;
398 }
399
400 $sFullDatabase = $sDatabase.$sAddition;
401
402 $sSql = "SELECT {$sDbIdName} as id, group_id as groupId
403 FROM {$sFullDatabase}";
404
405 $aDbObjects = $wpdb->get_results($sSql);
406
407 foreach ($aDbObjects as $oDbObject) {
408 $sSql = "INSERT INTO {$sDbAccessGroupToObject} (
409 group_id,
410 object_id,
411 object_type
412 )
413 VALUES(
414 '{$oDbObject->groupId}',
415 '{$oDbObject->id}',
416 '{$sObjectType}'
417 )";
418
419 $wpdb->query($sSql);
420 }
421 }
422
423 $wpdb->query(
424 "DROP TABLE {$sDbAccessGroupToPost},
425 {$sDbAccessGroupToUser},
426 {$sDbAccessGroupToCategory},
427 {$sDbAccessGroupToRole}"
428 );
429 }
430
431 if (version_compare($sCurrentDbVersion, "1.2", '<=')) {
432 $sDbAccessGroupToObject = $wpdb->prefix.'uam_accessgroup_to_object';
433
434 $sSql = "
435 ALTER TABLE `{$sDbAccessGroupToObject}`
436 CHANGE `object_id` `object_id` VARCHAR(64) NOT NULL,
437 CHANGE `object_type` `object_type` VARCHAR(64) NOT NULL";
438
439 $wpdb->query($sSql);
440 }
441
442 update_option('uam_db_version', $this->_sUamDbVersion);
443 }
444 }
445
446 /**
447 * Clean up wordpress if the plugin will be uninstalled.
448 *
449 * @return null
450 */
451 public function uninstall()
452 {
453 /**
454 * @var wpdb $wpdb
455 */
456 global $wpdb;
457
458 $wpdb->query(
459 "DROP TABLE ".DB_ACCESSGROUP.",
460 ".DB_ACCESSGROUP_TO_OBJECT
461 );
462
463 delete_option($this->_sAdminOptionsName);
464 delete_option('uam_version');
465 delete_option('uam_db_version');
466 $this->deleteHtaccessFiles();
467 }
468
469 /**
470 * Returns the database charset.
471 *
472 * @return string
473 */
474 protected function _getCharset()
475 {
476 global $wpdb;
477 $sCharsetCollate = '';
478
479 $sMySlqVersion = $wpdb->get_var("SELECT VERSION() as mysql_version");
480
481 if (version_compare($sMySlqVersion, '4.1.0', '>=')) {
482 if (!empty($wpdb->charset)) {
483 $sCharsetCollate = "DEFAULT CHARACTER SET $wpdb->charset";
484 }
485
486 if (!empty($wpdb->collate)) {
487 $sCharsetCollate.= " COLLATE $wpdb->collate";
488 }
489 }
490
491 return $sCharsetCollate;
492 }
493
494 /**
495 * Remove the htaccess file if the plugin is deactivated.
496 *
497 * @return null
498 */
499 public function deactivate()
500 {
501 $this->deleteHtaccessFiles();
502 }
503
504 /**
505 * Returns the current user.
506 *
507 * @return WP_User
508 */
509 public function getCurrentUser()
510 {
511 if (!function_exists('get_userdata')) {
512 include_once ABSPATH.'wp-includes/pluggable.php';
513 }
514
515 //Force user information
516 return wp_get_current_user();
517 }
518
519 /**
520 * Returns the full supported mine types.
521 *
522 * @return array
523 */
524 protected function _getMimeTypes()
525 {
526 if ($this->_aMimeTypes === null) {
527 $aMimeTypes = get_allowed_mime_types();
528 $aFullMimeTypes = array();
529
530 foreach ($aMimeTypes as $sExtensions => $sMineType) {
531 $aExtension = explode('|', $sExtensions);
532
533 foreach ($aExtension as $sExtension) {
534 $aFullMimeTypes[$sExtension] = $sMineType;
535 }
536 }
537
538 $this->_aMimeTypes = $aFullMimeTypes;
539 }
540
541 return $this->_aMimeTypes;
542 }
543
544 /**
545 * @param string $sFileTypes The file types which should be cleaned up.
546 *
547 * @return string
548 */
549 protected function _cleanUpFileTypesForHtaccess($sFileTypes)
550 {
551 $aValidFileTypes = array();
552 $aFileTypes = explode(',', $sFileTypes);
553 $aMimeTypes = $this->_getMimeTypes();
554
555 foreach ($aFileTypes as $sFileType) {
556 $sCleanFileType = trim($sFileType);
557
558 if (isset($aMimeTypes[$sCleanFileType])) {
559 $aValidFileTypes[$sCleanFileType] = $sCleanFileType;
560 }
561 }
562
563 return implode('|', $aValidFileTypes);
564 }
565
566 /**
567 * Creates a htaccess file.
568 *
569 * @param string $sDir The destination directory.
570 * @param string $sObjectType The object type.
571 *
572 * @return null.
573 */
574 public function createHtaccess($sDir = null, $sObjectType = null)
575 {
576 if ($sDir === null) {
577 $aWordpressUploadDir = wp_upload_dir();
578
579 if (empty($aWordpressUploadDir['error'])) {
580 $sDir = $aWordpressUploadDir['basedir'] . "/";
581 }
582 }
583
584 if ($sObjectType === null) {
585 $sObjectType = 'attachment';
586 }
587
588 if ($sDir !== null) {
589 if (!$this->isPermalinksActive()) {
590 $sAreaName = "WP-Files";
591 $aUamOptions = $this->getAdminOptions();
592
593 // make .htaccess and .htpasswd
594 $sHtaccessTxt = "";
595
596 if ($aUamOptions['lock_file_types'] == 'selected') {
597 $sFileTypes = $this->_cleanUpFileTypesForHtaccess($aUamOptions['locked_file_types']);
598 $sHtaccessTxt .= "<FilesMatch '\.(".$sFileTypes.")'>\n";
599 } elseif ($aUamOptions['lock_file_types'] == 'not_selected') {
600 $sFileTypes = $this->_cleanUpFileTypesForHtaccess($aUamOptions['not_locked_file_types']);
601 $sHtaccessTxt .= "<FilesMatch '^\.(".$sFileTypes.")'>\n";
602 }
603
604 $sHtaccessTxt .= "AuthType Basic" . "\n";
605 $sHtaccessTxt .= "AuthName \"" . $sAreaName . "\"" . "\n";
606 $sHtaccessTxt .= "AuthUserFile " . $sDir . ".htpasswd" . "\n";
607 $sHtaccessTxt .= "require valid-user" . "\n";
608
609 if ($aUamOptions['lock_file_types'] == 'selected'
610 || $aUamOptions['lock_file_types'] == 'not_selected'
611 ) {
612 $sHtaccessTxt.= "</FilesMatch>\n";
613 }
614 } else {
615 $aHomeRoot = parse_url(home_url());
616 if (isset($aHomeRoot['path'])) {
617 $aHomeRoot = trailingslashit($aHomeRoot['path']);
618 } else {
619 $aHomeRoot = '/';
620 }
621
622 $sHtaccessTxt = "<IfModule mod_rewrite.c>\n";
623 $sHtaccessTxt .= "RewriteEngine On\n";
624 $sHtaccessTxt .= "RewriteBase ".$aHomeRoot."\n";
625 $sHtaccessTxt .= "RewriteRule ^index\.php$ - [L]\n";
626 $sHtaccessTxt .= "RewriteRule (.*) ";
627 $sHtaccessTxt .= $aHomeRoot."index.php?uamfiletype=".$sObjectType."&uamgetfile=$1 [L]\n";
628 $sHtaccessTxt .= "</IfModule>\n";
629 }
630
631 // save files
632 $oFileHandler = fopen($sDir.".htaccess", "w");
633 fwrite($oFileHandler, $sHtaccessTxt);
634 fclose($oFileHandler);
635 }
636 }
637
638 /**
639 * Creates a htpasswd file.
640 *
641 * @param boolean $blCreateNew Force to create new file.
642 * @param string $sDir The destination directory.
643 *
644 * @return null
645 */
646 public function createHtpasswd($blCreateNew = false, $sDir = null)
647 {
648 $oCurrentUser = $this->getCurrentUser();
649 if (!function_exists('get_userdata')) {
650 include_once ABSPATH.'wp-includes/pluggable.php';
651 }
652
653 $aUamOptions = $this->getAdminOptions();
654
655 // get url
656 if ($sDir === null) {
657 $aWordpressUploadDir = wp_upload_dir();
658
659 if (empty($aWordpressUploadDir['error'])) {
660 $sDir = $aWordpressUploadDir['basedir'] . "/";
661 }
662 }
663
664 if ($sDir !== null) {
665 $oUserData = get_userdata($oCurrentUser->ID);
666
667 if (!file_exists($sDir.".htpasswd") || $blCreateNew) {
668 if ($aUamOptions['file_pass_type'] == 'random') {
669 $sPassword = md5($this->getRandomPassword());
670 } else {
671 $sPassword = $oUserData->user_pass;
672 }
673
674 $sUser = $oUserData->user_login;
675
676 // make .htpasswd
677 $sHtpasswdTxt = "$sUser:" . $sPassword . "\n";
678
679 // save file
680 $oFileHandler = fopen($sDir.".htpasswd", "w");
681 fwrite($oFileHandler, $sHtpasswdTxt);
682 fclose($oFileHandler);
683 }
684 }
685 }
686
687 /**
688 * Deletes the htaccess files.
689 *
690 * @param string $sDir The destination directory.
691 *
692 * @return null
693 */
694 public function deleteHtaccessFiles($sDir = null)
695 {
696 if ($sDir === null) {
697 $aWordpressUploadDir = wp_upload_dir();
698
699 if (empty($aWordpressUploadDir['error'])) {
700 $sDir = $aWordpressUploadDir['basedir'] . "/";
701 }
702 }
703
704 if ($sDir !== null) {
705 if (file_exists($sDir.".htaccess")) {
706 unlink($sDir.".htaccess");
707 }
708
709 if (file_exists($sDir.".htpasswd")) {
710 unlink($sDir.".htpasswd");
711 }
712 }
713 }
714
715 /**
716 * Generates and returns a random password.
717 *
718 * @return string
719 */
720 public function getRandomPassword()
721 {
722 //create password
723 $aArray = array();
724 $iLength = 16;
725
726 // numbers
727 for ($i = 48; $i < 58; $i++) {
728 $aArray[] = chr($i);
729 }
730
731 // small
732 for ($i = 97; $i < 122; $i++) {
733 $aArray[] = chr($i);
734 }
735
736 // capitals
737 for ($i = 65; $i < 90; $i++) {
738 $aArray[] = chr($i);
739 }
740
741 mt_srand((double)microtime() * 1000000);
742 $sPassword = '';
743
744 for ($i = 1; $i <= $iLength; $i++) {
745 $iRandomNumber = mt_rand(0, count($aArray) - 1);
746 $sPassword .= $aArray[$iRandomNumber];
747 }
748
749 return $sPassword;
750 }
751
752 /**
753 * Returns the current settings
754 *
755 * @return array
756 */
757 public function getAdminOptions()
758 {
759 if ($this->_aAdminOptions === null) {
760 $aUamAdminOptions = array(
761 'hide_post_title' => 'false',
762 'post_title' => __('No rights!', 'user-access-manager'),
763 'post_content' => __(
764 'Sorry you have no rights to view this post!',
765 'user-access-manager'
766 ),
767 'hide_post' => 'false',
768 'hide_post_comment' => 'false',
769 'post_comment_content' => __(
770 'Sorry no rights to view comments!',
771 'user-access-manager'
772 ),
773 'post_comments_locked' => 'false',
774 'hide_page_title' => 'false',
775 'page_title' => __('No rights!', 'user-access-manager'),
776 'page_content' => __(
777 'Sorry you have no rights to view this page!',
778 'user-access-manager'
779 ),
780 'hide_page' => 'false',
781 'hide_page_comment' => 'false',
782 'page_comment_content' => __(
783 'Sorry no rights to view comments!',
784 'user-access-manager'
785 ),
786 'page_comments_locked' => 'false',
787 'redirect' => 'false',
788 'redirect_custom_page' => '',
789 'redirect_custom_url' => '',
790 'lock_recursive' => 'true',
791 'authors_has_access_to_own' => 'true',
792 'authors_can_add_posts_to_groups' => 'false',
793 'lock_file' => 'false',
794 'file_pass_type' => 'random',
795 'lock_file_types' => 'all',
796 'download_type' => 'fopen',
797 'locked_file_types' => 'zip,rar,tar,gz',
798 'not_locked_file_types' => 'gif,jpg,jpeg,png',
799 'blog_admin_hint' => 'true',
800 'blog_admin_hint_text' => '[L]',
801 'hide_empty_categories' => 'true',
802 'protect_feed' => 'true',
803 'show_post_content_before_more' => 'false',
804 'full_access_role' => 'administrator'
805 );
806
807 $aUamOptions = $this->getWpOption($this->_sAdminOptionsName);
808
809 if (!empty($aUamOptions)) {
810 foreach ($aUamOptions as $sKey => $mOption) {
811 $aUamAdminOptions[$sKey] = $mOption;
812 }
813 }
814
815 update_option($this->_sAdminOptionsName, $aUamAdminOptions);
816 $this->_aAdminOptions = $aUamAdminOptions;
817 }
818
819 return $this->_aAdminOptions;
820 }
821
822 /**
823 * Returns the content of the excluded php file.
824 *
825 * @param string $sFileName The file name
826 * @param integer $iObjectId The _iId if needed.
827 * @param string $sObjectType The object type if needed.
828 *
829 * @return string
830 */
831 public function getIncludeContents($sFileName, $iObjectId = null, $sObjectType = null)
832 {
833 if (is_file($sFileName)) {
834 ob_start();
835 include $sFileName;
836 $sContents = ob_get_contents();
837 ob_end_clean();
838
839 return $sContents;
840 }
841
842 return '';
843 }
844
845 /**
846 * Returns the access handler object.
847 *
848 * @return UamAccessHandler
849 */
850 public function &getAccessHandler()
851 {
852 if ($this->_oAccessHandler == null) {
853 $this->_oAccessHandler = new UamAccessHandler($this);
854 }
855
856 return $this->_oAccessHandler;
857 }
858
859 /**
860 * Returns the current version of the user access manager.
861 *
862 * @return string
863 */
864 public function getVersion()
865 {
866 return $this->_sUamVersion;
867 }
868
869 /**
870 * Returns true if a user is at the admin panel.
871 *
872 * @return boolean
873 */
874 public function atAdminPanel()
875 {
876 return $this->_blAtAdminPanel;
877 }
878
879 /**
880 * Sets the atAdminPanel var to true.
881 *
882 * @return null
883 */
884 public function setAtAdminPanel()
885 {
886 $this->_blAtAdminPanel = true;
887 }
888
889
890 /*
891 * Helper functions.
892 */
893
894 /**
895 * Checks if a string starts with the given needle.
896 *
897 * @param string $sHaystack The haystack.
898 * @param string $sNeedle The needle.
899 *
900 * @return boolean
901 */
902 public function startsWith($sHaystack, $sNeedle)
903 {
904 return strpos($sHaystack, $sNeedle) === 0;
905 }
906
907
908 /*
909 * Functions for the admin panel content.
910 */
911
912 /**
913 * The function for the wp_print_styles action.
914 *
915 * @return null
916 */
917 public function addStyles()
918 {
919 wp_enqueue_style(
920 'UserAccessManagerAdmin',
921 UAM_URLPATH . "css/uamAdmin.css",
922 array() ,
923 '1.0',
924 'screen'
925 );
926
927 wp_enqueue_style(
928 'UserAccessManagerLoginForm',
929 UAM_URLPATH . "css/uamLoginForm.css",
930 array() ,
931 '1.0',
932 'screen'
933 );
934 }
935
936 /**
937 * The function for the wp_print_scripts action.
938 *
939 * @return null
940 */
941 public function addScripts()
942 {
943 wp_enqueue_script(
944 'UserAccessManagerFunctions',
945 UAM_URLPATH . 'js/functions.js',
946 array('jquery')
947 );
948 }
949
950 /**
951 * Prints the admin page.
952 *
953 * @return null
954 */
955 public function printAdminPage()
956 {
957 if (isset($_GET['page'])) {
958 $sAdminPage = $_GET['page'];
959
960 if ($sAdminPage == 'uam_settings') {
961 include UAM_REALPATH."tpl/adminSettings.php";
962 } elseif ($sAdminPage == 'uam_usergroup') {
963 include UAM_REALPATH."tpl/adminGroup.php";
964 } elseif ($sAdminPage == 'uam_setup') {
965 include UAM_REALPATH."tpl/adminSetup.php";
966 } elseif ($sAdminPage == 'uam_about') {
967 include UAM_REALPATH."tpl/about.php";
968 }
969 }
970 }
971
972 /**
973 * Shows the error if the user has no rights to edit the content.
974 *
975 * @return null
976 */
977 public function noRightsToEditContent()
978 {
979 $blNoRights = false;
980
981 if (isset($_GET['post']) && is_numeric($_GET['post'])) {
982 $oPost = $this->getPost($_GET['post']);
983 $blNoRights = !$this->getAccessHandler()->checkObjectAccess( $oPost->post_type, $oPost->ID );
984 }
985
986 if (isset($_GET['attachment_id']) && is_numeric($_GET['attachment_id']) && !$blNoRights) {
987 $oPost = $this->getPost($_GET['attachment_id']);
988 $blNoRights = !$this->getAccessHandler()->checkObjectAccess($oPost->post_type, $oPost->ID);
989 }
990
991 if (isset($_GET['tag_ID']) && is_numeric($_GET['tag_ID']) && !$blNoRights) {
992 $blNoRights = !$this->getAccessHandler()->checkObjectAccess('category', $_GET['tag_ID']);
993 }
994
995 if ($blNoRights) {
996 wp_die(TXT_UAM_NO_RIGHTS);
997 }
998 }
999
1000 /**
1001 * The function for the wp_dashboard_setup action.
1002 * Removes widgets to which a user should not have access.
1003 *
1004 * @return null
1005 */
1006 public function setupAdminDashboard()
1007 {
1008 global $wp_meta_boxes;
1009
1010 if (!$this->getAccessHandler()->checkUserAccess('manage_user_groups')) {
1011 unset($wp_meta_boxes['dashboard']['normal']['core']['dashboard_recent_comments']);
1012 }
1013 }
1014
1015 /**
1016 * The function for the update_option_permalink_structure action.
1017 *
1018 * @return null
1019 */
1020 public function updatePermalink()
1021 {
1022 $this->createHtaccess();
1023 $this->createHtpasswd();
1024 }
1025
1026
1027 /*
1028 * Meta functions
1029 */
1030
1031 /**
1032 * Saves the object data to the database.
1033 *
1034 * @param string $sObjectType The object type.
1035 * @param integer $iObjectId The _iId of the object.
1036 * @param array $aUserGroups The new usergroups for the object.
1037 *
1038 * @return null
1039 */
1040 protected function _saveObjectData($sObjectType, $iObjectId, $aUserGroups = null)
1041 {
1042 $oUamAccessHandler = $this->getAccessHandler();
1043 $oUamOptions = $this->getAdminOptions();
1044 $aFormData = array();
1045
1046 if (isset($_POST['uam_update_groups'])) {
1047 $aFormData = $_POST;
1048 } elseif (isset($_GET['uam_update_groups'])) {
1049 $aFormData = $_GET;
1050 }
1051
1052 if (isset($aFormData['uam_update_groups'])
1053 && ($oUamAccessHandler->checkUserAccess('manage_user_groups')
1054 || $oUamOptions['authors_can_add_posts_to_groups'] == 'true')
1055 ) {
1056 if ($aUserGroups === null) {
1057 $aUserGroups = isset($aFormData['uam_usergroups']) ? $aFormData['uam_usergroups'] : array();
1058 }
1059
1060 $aAddUserGroups = array_flip($aUserGroups);
1061 $aRemoveUserGroups = $oUamAccessHandler->getUserGroupsForObject($sObjectType, $iObjectId);
1062 $aUamUserGroups = $oUamAccessHandler->getUserGroups();
1063 $blRemoveOldAssignments = true;
1064
1065 if (isset($aFormData['uam_bulk_type'])) {
1066 $sBulkType = $aFormData['uam_bulk_type'];
1067
1068 if ($sBulkType === 'add') {
1069 $blRemoveOldAssignments = false;
1070 } elseif ($sBulkType === 'remove') {
1071 $aRemoveUserGroups = $aAddUserGroups;
1072 $aAddUserGroups = array();
1073 }
1074 }
1075
1076 foreach ($aUamUserGroups as $sGroupId => $oUamUserGroup) {
1077 if (isset($aRemoveUserGroups[$sGroupId])) {
1078 $oUamUserGroup->removeObject($sObjectType, $iObjectId);
1079 }
1080
1081 if (isset($aAddUserGroups[$sGroupId])) {
1082 $oUamUserGroup->addObject($sObjectType, $iObjectId);
1083 }
1084
1085 $oUamUserGroup->save($blRemoveOldAssignments);
1086 }
1087 }
1088 }
1089
1090
1091 /*
1092 * Functions for the post actions.
1093 */
1094
1095 /**
1096 * The function for the manage_posts_columns and
1097 * the manage_pages_columns filter.
1098 *
1099 * @param array $aDefaults The table headers.
1100 *
1101 * @return array
1102 */
1103 public function addPostColumnsHeader($aDefaults)
1104 {
1105 $aDefaults['uam_access'] = __('Access', 'user-access-manager');
1106 return $aDefaults;
1107 }
1108
1109 /**
1110 * The function for the manage_users_custom_column action.
1111 *
1112 * @param string $sColumnName The column name.
1113 * @param integer $iId The _iId.
1114 *
1115 * @return string
1116 */
1117 public function addPostColumn($sColumnName, $iId)
1118 {
1119 if ($sColumnName == 'uam_access') {
1120 $oPost = $this->getPost($iId);
1121 echo $this->getIncludeContents(UAM_REALPATH.'tpl/objectColumn.php', $oPost->ID, $oPost->post_type);
1122 }
1123 }
1124
1125 /**
1126 * The function for the uma_post_access metabox.
1127 *
1128 * @param object $oPost The post.
1129 *
1130 * @return null;
1131 */
1132 public function editPostContent($oPost)
1133 {
1134 $iObjectId = $oPost->ID;
1135 include UAM_REALPATH.'tpl/postEditForm.php';
1136 }
1137
1138 public function addBulkAction($sColumnName)
1139 {
1140 if ($sColumnName == 'uam_access') {
1141 include UAM_REALPATH.'tpl/bulkEditForm.php';
1142 }
1143 }
1144
1145 /**
1146 * The function for the save_post action.
1147 *
1148 * @param mixed $mPostParam The post _iId or a array of a post.
1149 *
1150 * @return null
1151 */
1152 public function savePostData($mPostParam)
1153 {
1154 if (is_array($mPostParam)) {
1155 $oPost = $this->getPost($mPostParam['ID']);
1156 } else {
1157 $oPost = $this->getPost($mPostParam);
1158 }
1159
1160 $iPostId = $oPost->ID;
1161 $sPostType = $oPost->post_type;
1162
1163 if ($sPostType == 'revision') {
1164 $iPostId = $oPost->post_parent;
1165 $oParentPost = $this->getPost($iPostId);
1166 $sPostType = $oParentPost->post_type;
1167 }
1168
1169 $this->_saveObjectData($sPostType, $iPostId);
1170 }
1171
1172 /**
1173 * The function for the attachment_fields_to_save filter.
1174 * We have to use this because the attachment actions work
1175 * not in the way we need.
1176 *
1177 * @param object $oAttachment The attachment _iId.
1178 *
1179 * @return object
1180 */
1181 public function saveAttachmentData($oAttachment)
1182 {
1183 $this->savePostData($oAttachment['ID']);
1184
1185 return $oAttachment;
1186 }
1187
1188 /**
1189 * The function for the delete_post action.
1190 *
1191 * @param integer $iPostId The post _iId.
1192 *
1193 * @return null
1194 */
1195 public function removePostData($iPostId)
1196 {
1197 /**
1198 * @var wpdb $wpdb
1199 */
1200 global $wpdb;
1201 $oPost = $this->getPost($iPostId);
1202
1203 $wpdb->query(
1204 "DELETE FROM " . DB_ACCESSGROUP_TO_OBJECT . "
1205 WHERE object_id = '".$iPostId."'
1206 AND object_type = '".$oPost->post_type."'"
1207 );
1208 }
1209
1210 /**
1211 * The function for the media_meta action.
1212 *
1213 * @param string $sMeta The meta.
1214 * @param object $oPost The post.
1215 *
1216 * @return string
1217 */
1218 public function showMediaFile($sMeta = '', $oPost = null)
1219 {
1220 $sContent = $sMeta;
1221 $sContent .= '</td></tr><tr>';
1222 $sContent .= '<th class="label">';
1223 $sContent .= '<label>'.TXT_UAM_SET_UP_USERGROUPS.'</label>';
1224 $sContent .= '</th>';
1225 $sContent .= '<td class="field">';
1226 $sContent .= $this->getIncludeContents(UAM_REALPATH.'tpl/postEditForm.php', $oPost->ID);
1227
1228 return $sContent;
1229 }
1230
1231
1232 /*
1233 * Functions for the user actions.
1234 */
1235
1236 /**
1237 * The function for the manage_users_columns filter.
1238 *
1239 * @param array $aDefaults The table headers.
1240 *
1241 * @return array
1242 */
1243 public function addUserColumnsHeader($aDefaults)
1244 {
1245 $aDefaults['uam_access'] = __('uam user groups');
1246 return $aDefaults;
1247 }
1248
1249 /**
1250 * The function for the manage_users_custom_column action.
1251 *
1252 * @param string $sReturn The normal return value.
1253 * @param string $sColumnName The column name.
1254 * @param integer $iId The _iId.
1255 *
1256 * @return string|null
1257 */
1258 public function addUserColumn($sReturn, $sColumnName, $iId)
1259 {
1260 if ($sColumnName == 'uam_access') {
1261 return $this->getIncludeContents(UAM_REALPATH.'tpl/userColumn.php', $iId, 'user');
1262 }
1263
1264 return $sReturn;
1265 }
1266
1267 /**
1268 * The function for the edit_user_profile action.
1269 *
1270 * @return null
1271 */
1272 public function showUserProfile()
1273 {
1274 echo $this->getIncludeContents(UAM_REALPATH.'tpl/userProfileEditForm.php');
1275 }
1276
1277 /**
1278 * The function for the profile_update action.
1279 *
1280 * @param integer $iUserId The user _iId.
1281 *
1282 * @return null
1283 */
1284 public function saveUserData($iUserId)
1285 {
1286 $this->_saveObjectData('user', $iUserId);
1287 }
1288
1289 /**
1290 * The function for the delete_user action.
1291 *
1292 * @param integer $iUserId The user _iId.
1293 *
1294 * @return null
1295 */
1296 public function removeUserData($iUserId)
1297 {
1298 /**
1299 * @var wpdb $wpdb
1300 */
1301 global $wpdb;
1302
1303 $wpdb->query(
1304 "DELETE FROM " . DB_ACCESSGROUP_TO_OBJECT . "
1305 WHERE object_id = ".$iUserId."
1306 AND object_type = 'user'"
1307 );
1308 }
1309
1310
1311 /*
1312 * Functions for the category actions.
1313 */
1314
1315 /**
1316 * The function for the manage_categories_columns filter.
1317 *
1318 * @param array $aDefaults The table headers.
1319 *
1320 * @return array
1321 */
1322 public function addCategoryColumnsHeader($aDefaults)
1323 {
1324 $aDefaults['uam_access'] = __('Access', 'user-access-manager');
1325 return $aDefaults;
1326 }
1327
1328 /**
1329 * The function for the manage_categories_custom_column action.
1330 *
1331 * @param string $sEmpty An empty string from wordpress? What the hell?!?
1332 * @param string $sColumnName The column name.
1333 * @param integer $iId The _iId.
1334 *
1335 * @return string|null
1336 */
1337 public function addCategoryColumn($sEmpty, $sColumnName, $iId)
1338 {
1339 if ($sColumnName == 'uam_access') {
1340 return $this->getIncludeContents(UAM_REALPATH.'tpl/objectColumn.php', $iId, 'category');
1341 }
1342
1343 return null;
1344 }
1345
1346 /**
1347 * The function for the edit_category_form action.
1348 *
1349 * @param object $oCategory The category.
1350 *
1351 * @return null
1352 */
1353 public function showCategoryEditForm($oCategory)
1354 {
1355 include UAM_REALPATH.'tpl/categoryEditForm.php';
1356 }
1357
1358 /**
1359 * The function for the edit_category action.
1360 *
1361 * @param integer $iCategoryId The category _iId.
1362 *
1363 * @return null
1364 */
1365 public function saveCategoryData($iCategoryId)
1366 {
1367 $this->_saveObjectData('category', $iCategoryId);
1368 }
1369
1370 /**
1371 * The function for the delete_category action.
1372 *
1373 * @param integer $iCategoryId The _iId of the category.
1374 *
1375 * @return null
1376 */
1377 public function removeCategoryData($iCategoryId)
1378 {
1379 /**
1380 * @var wpdb $wpdb
1381 */
1382 global $wpdb;
1383
1384 $wpdb->query(
1385 "DELETE FROM " . DB_ACCESSGROUP_TO_OBJECT . "
1386 WHERE object_id = ".$iCategoryId."
1387 AND object_type = 'category'"
1388 );
1389 }
1390
1391
1392 /*
1393 * Functions for the pluggable object actions.
1394 */
1395
1396 /**
1397 * The function for the pluggable save action.
1398 *
1399 * @param string $sObjectType The name of the pluggable object.
1400 * @param integer $iObjectId The pluggable object _iId.
1401 * @param array $aUserGroups The user groups for the object.
1402 *
1403 * @return null
1404 */
1405 public function savePlObjectData($sObjectType, $iObjectId, $aUserGroups = null)
1406 {
1407 $this->_saveObjectData($sObjectType, $iObjectId, $aUserGroups);
1408 }
1409
1410 /**
1411 * The function for the pluggable remove action.
1412 *
1413 * @param string $sObjectName The name of the pluggable object.
1414 * @param integer $iObjectId The pluggable object _iId.
1415 *
1416 * @return null
1417 */
1418 public function removePlObjectData($sObjectName, $iObjectId)
1419 {
1420 /**
1421 * @var wpdb $wpdb
1422 */
1423 global $wpdb;
1424
1425 $wpdb->query(
1426 "DELETE FROM " . DB_ACCESSGROUP_TO_OBJECT . "
1427 WHERE object_id = ".$iObjectId."
1428 AND object_type = ".$sObjectName
1429 );
1430 }
1431
1432 /**
1433 * Returns the group selection form for pluggable _aObjects.
1434 *
1435 * @param string $sObjectType The object type.
1436 * @param integer $iObjectId The _iId of the object.
1437 * @param string $aGroupsFormName The name of the form which contains the groups.
1438 *
1439 * @return string;
1440 */
1441 public function showPlGroupSelectionForm($sObjectType, $iObjectId, $aGroupsFormName = null)
1442 {
1443 $sFileName = UAM_REALPATH.'tpl/groupSelectionForm.php';
1444 $aUamUserGroups = $this->getAccessHandler()->getUserGroups();
1445 $aUserGroupsForObject = $this->getAccessHandler()->getUserGroupsForObject($sObjectType, $iObjectId);
1446
1447 if (is_file($sFileName)) {
1448 ob_start();
1449 include $sFileName;
1450 $sContents = ob_get_contents();
1451 ob_end_clean();
1452
1453 return $sContents;
1454 }
1455
1456 return '';
1457 }
1458
1459 /**
1460 * Returns the column for a pluggable object.
1461 *
1462 * @param string $sObjectType The object type.
1463 * @param integer $iObjectId The object _iId.
1464 *
1465 * @return string
1466 */
1467 public function getPlColumn($sObjectType, $iObjectId)
1468 {
1469 return $this->getIncludeContents(UAM_REALPATH.'tpl/objectColumn.php', $iObjectId, $sObjectType);
1470 }
1471
1472
1473 /*
1474 * Functions for the blog content.
1475 */
1476
1477 /**
1478 * Manipulates the wordpress query object to filter content.
1479 *
1480 * @param object $oWpQuery The wordpress query object.
1481 *
1482 * @return null
1483 */
1484 public function parseQuery($oWpQuery)
1485 {
1486 $aUamOptions = $this->getAdminOptions();
1487
1488 if ($aUamOptions['hide_post'] == 'true') {
1489 $oUamAccessHandler = $this->getAccessHandler();
1490 $aExcludedPosts = $oUamAccessHandler->getExcludedPosts();
1491
1492 if (count($aExcludedPosts) > 0) {
1493 $oWpQuery->query_vars['post__not_in'] = array_merge(
1494 $oWpQuery->query_vars['post__not_in'],
1495 $aExcludedPosts
1496 );
1497 }
1498 }
1499 }
1500
1501 /**
1502 * Modifies the content of the post by the given settings.
1503 *
1504 * @param object $oPost The current post.
1505 *
1506 * @return object|null
1507 */
1508 protected function _getPost($oPost)
1509 {
1510 $aUamOptions = $this->getAdminOptions();
1511 $oUamAccessHandler = $this->getAccessHandler();
1512
1513 $sPostType = $oPost->post_type;
1514
1515 if ($this->getAccessHandler()->isPostableType($sPostType) && $sPostType != 'post' && $sPostType != 'page') {
1516 $sPostType = 'post';
1517 } elseif ($sPostType != 'post' && $sPostType != 'page') {
1518 return $oPost;
1519 }
1520
1521 if ($aUamOptions['hide_'.$sPostType] == 'true' || $this->atAdminPanel()) {
1522 if ($oUamAccessHandler->checkObjectAccess($oPost->post_type, $oPost->ID)) {
1523 $oPost->post_title .= $this->adminOutput($oPost->post_type, $oPost->ID);
1524 return $oPost;
1525 }
1526 } else {
1527 if (!$oUamAccessHandler->checkObjectAccess($oPost->post_type, $oPost->ID)) {
1528 $oPost->isLocked = true;
1529
1530 $sUamPostContent = $aUamOptions[$sPostType.'_content'];
1531 $sUamPostContent = str_replace("[LOGIN_FORM]", $this->getLoginBarHtml(), $sUamPostContent);
1532
1533 if ($aUamOptions['hide_'.$sPostType.'_title'] == 'true') {
1534 $oPost->post_title = $aUamOptions[$sPostType.'_title'];
1535 }
1536
1537 if ($aUamOptions[$sPostType.'_comments_locked'] == 'false') {
1538 $oPost->comment_status = 'close';
1539 }
1540
1541 if ($aUamOptions['show_post_content_before_more'] == 'true'
1542 && $sPostType == "post"
1543 && preg_match('/<!--more(.*?)?-->/', $oPost->post_content, $aMatches)
1544 ) {
1545 $oPost->post_content = explode($aMatches[0], $oPost->post_content, 2);
1546 $sUamPostContent = $oPost->post_content[0] . " " . $sUamPostContent;
1547 }
1548
1549 $oPost->post_content = stripslashes($sUamPostContent);
1550 }
1551
1552 $oPost->post_title .= $this->adminOutput($oPost->post_type, $oPost->ID);
1553
1554 return $oPost;
1555 }
1556
1557 return null;
1558 }
1559
1560 /**
1561 * The function for the the_posts filter.
1562 *
1563 * @param array $aPosts The posts.
1564 *
1565 * @return array
1566 */
1567 public function showPost($aPosts = array())
1568 {
1569 $aShowPosts = array();
1570 $aUamOptions = $this->getAdminOptions();
1571
1572 if (!is_feed() || ($aUamOptions['protect_feed'] == 'true' && is_feed())) {
1573 foreach ($aPosts as $iPostId) {
1574 if ($iPostId !== null) {
1575 $oPost = $this->_getPost($iPostId);
1576
1577 if ($oPost !== null) {
1578 $aShowPosts[] = $oPost;
1579 }
1580 }
1581 }
1582
1583 $aPosts = $aShowPosts;
1584 }
1585
1586 return $aPosts;
1587 }
1588
1589 /**
1590 * The function for the posts_where_paged filter.
1591 *
1592 * @param string $sSql The where sql statement.
1593 *
1594 * @return string
1595 */
1596 public function showPostSql($sSql)
1597 {
1598 $oUamAccessHandler = $this->getAccessHandler();
1599 $aUamOptions = $this->getAdminOptions();
1600
1601 if ($aUamOptions['hide_post'] == 'true') {
1602 global $wpdb;
1603 $aExcludedPosts = $oUamAccessHandler->getExcludedPosts();
1604
1605 if (count($aExcludedPosts) > 0) {
1606 $sExcludedPostsStr = implode(",", $aExcludedPosts);
1607 $sSql .= " AND $wpdb->posts.ID NOT IN($sExcludedPostsStr) ";
1608 }
1609 }
1610
1611 return $sSql;
1612 }
1613
1614 /**
1615 * The function for the wp_get_nav_menu_items filter.
1616 *
1617 * @param array $aItems The menu item.
1618 *
1619 * @return array
1620 */
1621 public function showCustomMenu($aItems)
1622 {
1623 $aShowItems = array();
1624
1625 foreach ($aItems as $oItem) {
1626 if ($oItem->object == 'post' || $oItem->object == 'page') {
1627 $oObject = $this->getPost($oItem->object_id);
1628
1629 if ($oObject !== null) {
1630 $oPost = $this->_getPost($oObject);
1631
1632 if ($oPost !== null) {
1633 if (isset($oPost->isLocked)) {
1634 $oItem->title = $oPost->post_title;
1635 }
1636
1637 $oItem->title .= $this->adminOutput($oItem->object, $oItem->object_id);
1638 $aShowItems[] = $oItem;
1639 }
1640 }
1641 } elseif ($oItem->object == 'category') {
1642 $oObject = $this->getCategory($oItem->object_id);
1643 $oCategory = $this->_getTerm('category', $oObject);
1644
1645 if ($oCategory !== null && !$oCategory->isEmpty) {
1646 $oItem->title .= $this->adminOutput($oItem->object, $oItem->object_id);
1647 $aShowItems[] = $oItem;
1648 }
1649 } else {
1650 $aShowItems[] = $oItem;
1651 }
1652 }
1653
1654 return $aShowItems;
1655 }
1656
1657 /**
1658 * The function for the comments_array filter.
1659 *
1660 * @param array $aComments The comments.
1661 *
1662 * @return array
1663 */
1664 public function showComment($aComments = array())
1665 {
1666 $aShowComments = array();
1667 $aUamOptions = $this->getAdminOptions();
1668 $oUamAccessHandler = $this->getAccessHandler();
1669
1670 foreach ($aComments as $oComment) {
1671 $oPost = $this->getPost($oComment->comment_post_ID);
1672 $sPostType = $oPost->post_type;
1673
1674 if ($aUamOptions['hide_'.$sPostType.'_comment'] == 'true'
1675 || $aUamOptions['hide_'.$sPostType] == 'true'
1676 || $this->atAdminPanel()
1677 ) {
1678 if ($oUamAccessHandler->checkObjectAccess($oPost->post_type, $oPost->ID)) {
1679 $aShowComments[] = $oComment;
1680 }
1681 } else {
1682 if (!$oUamAccessHandler->checkObjectAccess($oPost->post_type, $oPost->ID)) {
1683 $oComment->comment_content = $aUamOptions[$sPostType.'_comment_content'];
1684 }
1685
1686 $aShowComments[] = $oComment;
1687 }
1688 }
1689
1690 $aComments = $aShowComments;
1691
1692 return $aComments;
1693 }
1694
1695 /**
1696 * The function for the get_pages filter.
1697 *
1698 * @param array $aPages The pages.
1699 *
1700 * @return array
1701 */
1702 public function showPage($aPages = array())
1703 {
1704 $aShowPages = array();
1705 $aUamOptions = $this->getAdminOptions();
1706 $oUamAccessHandler = $this->getAccessHandler();
1707
1708 foreach ($aPages as $oPage) {
1709 if ($aUamOptions['hide_page'] == 'true'
1710 || $this->atAdminPanel()
1711 ) {
1712 if ($oUamAccessHandler->checkObjectAccess($oPage->post_type, $oPage->ID)) {
1713 $oPage->post_title .= $this->adminOutput(
1714 $oPage->post_type,
1715 $oPage->ID
1716 );
1717 $aShowPages[] = $oPage;
1718 }
1719 } else {
1720 if (!$oUamAccessHandler->checkObjectAccess($oPage->post_type, $oPage->ID)) {
1721 if ($aUamOptions['hide_page_title'] == 'true') {
1722 $oPage->post_title = $aUamOptions['page_title'];
1723 }
1724
1725 $oPage->post_content = $aUamOptions['page_content'];
1726 }
1727
1728 $oPage->post_title .= $this->adminOutput($oPage->post_type, $oPage->ID);
1729 $aShowPages[] = $oPage;
1730 }
1731 }
1732
1733 $aPages = $aShowPages;
1734
1735 return $aPages;
1736 }
1737
1738 /**
1739 * Modifies the content of the term by the given settings.
1740 *
1741 * @param string $sTermType The type of the term.
1742 * @param object $oTerm The current term.
1743 *
1744 * @return object|null
1745 */
1746 protected function _getTerm($sTermType, $oTerm)
1747 {
1748 $aUamOptions = $this->getAdminOptions();
1749 $oUamAccessHandler = $this->getAccessHandler();
1750
1751 $oTerm->isEmpty = false;
1752
1753 $oTerm->name .= $this->adminOutput('term', $oTerm->term_id);
1754
1755 if ($sTermType == 'post_tag'
1756 || ( $sTermType == 'category' || $sTermType == $oTerm->taxonomy)
1757 && $oUamAccessHandler->checkObjectAccess('category', $oTerm->term_id)
1758 ) {
1759 if ($this->atAdminPanel() == false
1760 && ($aUamOptions['hide_post'] == 'true'
1761 || $aUamOptions['hide_page'] == 'true')
1762 ) {
1763 $iTermRequest = $oTerm->term_id;
1764 $sTermRequestType = $sTermType;
1765
1766 if ($sTermType == 'post_tag') {
1767 $iTermRequest = $oTerm->slug;
1768 $sTermRequestType = 'tag';
1769 }
1770
1771 $aArgs = array(
1772 'numberposts' => - 1,
1773 $sTermRequestType => $iTermRequest
1774 );
1775
1776 $aTermPosts = get_posts($aArgs);
1777 $oTerm->count = count($aTermPosts);
1778
1779 if (isset($aTermPosts)) {
1780 foreach ($aTermPosts as $oPost) {
1781 if ($aUamOptions['hide_'.$oPost->post_type] == 'true'
1782 && !$oUamAccessHandler->checkObjectAccess($oPost->post_type, $oPost->ID)
1783 ) {
1784 $oTerm->count--;
1785 }
1786 }
1787 }
1788
1789 //For post_tags
1790 if ($sTermType == 'post_tag' && $oTerm->count <= 0) {
1791 return null;
1792 }
1793
1794 //For categories
1795 if ($oTerm->count <= 0
1796 && $aUamOptions['hide_empty_categories'] == 'true'
1797 && ($oTerm->taxonomy == "term"
1798 || $oTerm->taxonomy == "category")
1799 ) {
1800 $oTerm->isEmpty = true;
1801 }
1802
1803 if ($aUamOptions['lock_recursive'] == 'false') {
1804 $oCurCategory = $oTerm;
1805
1806 while ($oCurCategory->parent != 0) {
1807 $oCurCategory = get_term($oCurCategory->parent, 'category');
1808
1809 if ($oUamAccessHandler->checkObjectAccess('term', $oCurCategory->term_id)) {
1810 $oTerm->parent = $oCurCategory->term_id;
1811 break;
1812 }
1813 }
1814 }
1815 }
1816
1817 return $oTerm;
1818 }
1819
1820 return null;
1821 }
1822
1823 /**
1824 * The function for the get_terms filter.
1825 *
1826 * @param array $aTerms The terms.
1827 * @param array $aArgs The given arguments.
1828 *
1829 * @return array
1830 */
1831 public function showTerms($aTerms = array(), $aArgs = array())
1832 {
1833 $aShowTerms = array();
1834
1835 foreach ($aTerms as $oTerm) {
1836 if (!is_object($oTerm)) {
1837 return $aTerms;
1838 }
1839
1840 if ($oTerm->taxonomy == 'category' || $oTerm->taxonomy == 'post_tag') {
1841 $oTerm = $this->_getTerm($oTerm->taxonomy, $oTerm);
1842 }
1843
1844 if ($oTerm !== null && (!isset($oTerm->isEmpty) || !$oTerm->isEmpty)) {
1845 $aShowTerms[$oTerm->term_id] = $oTerm;
1846 }
1847 }
1848
1849 foreach ($aTerms as $sKey => $oTerm) {
1850 if (!isset($aShowTerms[$oTerm->term_id])) {
1851 unset($aTerms[$sKey]);
1852 }
1853 }
1854
1855 return $aTerms;
1856 }
1857
1858 /**
1859 * The function for the get_previous_post_where and
1860 * the get_next_post_where filter.
1861 *
1862 * @param string $sSql The current sql string.
1863 *
1864 * @return string
1865 */
1866 public function showNextPreviousPost($sSql)
1867 {
1868 $oUamAccessHandler = $this->getAccessHandler();
1869 $aUamOptions = $this->getAdminOptions();
1870
1871 if ($aUamOptions['hide_post'] == 'true') {
1872 $aExcludedPosts = $oUamAccessHandler->getExcludedPosts();
1873
1874 if (count($aExcludedPosts) > 0) {
1875 $sExcludedPosts = implode(",", $aExcludedPosts);
1876 $sSql.= " AND p.ID NOT IN($sExcludedPosts) ";
1877 }
1878 }
1879
1880 return $sSql;
1881 }
1882
1883 /**
1884 * Returns the admin hint.
1885 *
1886 * @param string $sObjectType The object type.
1887 * @param integer $iObjectId The object _iId we want to check.
1888 *
1889 * @return string
1890 */
1891 public function adminOutput($sObjectType, $iObjectId)
1892 {
1893 $sOutput = "";
1894
1895 if (!$this->atAdminPanel()) {
1896 $aUamOptions = $this->getAdminOptions();
1897
1898 if ($aUamOptions['blog_admin_hint'] == 'true') {
1899 $oCurrentUser = $this->getCurrentUser();
1900
1901 $oUserData = get_userdata($oCurrentUser->ID);
1902
1903 if (!isset($oUserData->user_level)) {
1904 return $sOutput;
1905 }
1906
1907 $oUamAccessHandler = $this->getAccessHandler();
1908
1909 if ($oUamAccessHandler->userIsAdmin($oCurrentUser->ID)
1910 && count($oUamAccessHandler->getUserGroupsForObject($sObjectType, $iObjectId)) > 0
1911 ) {
1912 $sOutput .= $aUamOptions['blog_admin_hint_text'];
1913 }
1914 }
1915 }
1916
1917 return $sOutput;
1918 }
1919
1920 /**
1921 * The function for the edit_post_link filter.
1922 *
1923 * @param string $sLink The edit link.
1924 * @param integer $iPostId The _iId of the post.
1925 *
1926 * @return string
1927 */
1928 public function showGroupMembership($sLink, $iPostId)
1929 {
1930 $oUamAccessHandler = $this->getAccessHandler();
1931 $aGroups = $oUamAccessHandler->getUserGroupsForObject('post', $iPostId);
1932
1933 if (count($aGroups) > 0) {
1934 $sLink .= ' | '.TXT_UAM_ASSIGNED_GROUPS.': ';
1935
1936 foreach ($aGroups as $oGroup) {
1937 $sLink .= $oGroup->getGroupName().', ';
1938 }
1939
1940 $sLink = rtrim($sLink, ', ');
1941 }
1942
1943 return $sLink;
1944 }
1945
1946 /**
1947 * Returns the login bar.
1948 *
1949 * @return string
1950 */
1951 public function getLoginBarHtml()
1952 {
1953 if (!is_user_logged_in()) {
1954 return $this->getIncludeContents(UAM_REALPATH.'tpl/loginBar.php');
1955 }
1956
1957 return '';
1958 }
1959
1960
1961 /*
1962 * Functions for the redirection and files.
1963 */
1964
1965 /**
1966 * Returns true if permalinks are active otherwise false.
1967 *
1968 * @return boolean
1969 */
1970 public function isPermalinksActive()
1971 {
1972 $sPermalinkStructure = $this->getWpOption('permalink_structure');
1973
1974 if (empty($sPermalinkStructure)) {
1975 return false;
1976 } else {
1977 return true;
1978 }
1979 }
1980
1981 /**
1982 * Redirects to a page or to content.
1983 *
1984 * @param string $sHeaders The headers which are given from wordpress.
1985 * @param object $oPageParams The params of the current page.
1986 *
1987 * @return string
1988 */
1989 public function redirect($sHeaders, $oPageParams)
1990 {
1991 $oUamOptions = $this->getAdminOptions();
1992
1993 if (isset($_GET['uamgetfile']) && isset($_GET['uamfiletype'])) {
1994 $sFileUrl = $_GET['uamgetfile'];
1995 $sFileType = $_GET['uamfiletype'];
1996 $this->getFile($sFileType, $sFileUrl);
1997 } elseif (!$this->atAdminPanel() && $oUamOptions['redirect'] !== 'false') {
1998 $oObject = null;
1999
2000 if (isset($oPageParams->query_vars['p'])) {
2001 $oObject = $this->getPost($oPageParams->query_vars['p']);
2002 $oObjectType = $oObject->post_type;
2003 $iObjectId = $oObject->ID;
2004 } elseif (isset($oPageParams->query_vars['page_id'])) {
2005 $oObject = $this->getPost($oPageParams->query_vars['page_id']);
2006 $oObjectType = $oObject->post_type;
2007 $iObjectId = $oObject->ID;
2008 } elseif (isset($oPageParams->query_vars['cat_id'])) {
2009 $oObject = $this->getCategory($oPageParams->query_vars['cat_id']);
2010 $oObjectType = 'category';
2011 $iObjectId = $oObject->term_id;
2012 } elseif (isset($oPageParams->query_vars['name'])) {
2013 global $wpdb;
2014
2015 $sQuery = $wpdb->prepare(
2016 "SELECT ID
2017 FROM {$wpdb->posts}
2018 WHERE post_name = %s
2019 AND post_type IN ('post', 'page')",
2020 $oPageParams->query_vars['name']
2021 );
2022
2023 $sObjectId = $wpdb->get_var($sQuery);
2024
2025 if ($sObjectId) {
2026 $oObject = get_post($sObjectId);
2027 }
2028
2029 if ($oObject !== null) {
2030 $oObjectType = $oObject->post_type;
2031 $iObjectId = $oObject->ID;
2032 }
2033 } elseif (isset($oPageParams->query_vars['pagename'])) {
2034 $oObject = get_page_by_title($oPageParams->query_vars['pagename']);
2035
2036 if ($oObject !== null) {
2037 $oObjectType = $oObject->post_type;
2038 $iObjectId = $oObject->ID;
2039 }
2040 }
2041
2042 if ($oObject === null || $oObject !== null && isset($oObjectType) && isset($iObjectId)
2043 && !$this->getAccessHandler()->checkObjectAccess($oObjectType, $iObjectId)
2044 ) {
2045 $this->redirectUser($oObject);
2046 }
2047 }
2048
2049 return $sHeaders;
2050 }
2051
2052 /**
2053 * Returns the current url.
2054 *
2055 * @return string
2056 */
2057 public function getCurrentUrl()
2058 {
2059 if (!isset($_SERVER['REQUEST_URI'])) {
2060 $sServerRequestUri = $_SERVER['PHP_SELF'];
2061 } else {
2062 $sServerRequestUri = $_SERVER['REQUEST_URI'];
2063 }
2064
2065 $sSecure = empty($_SERVER["HTTPS"]) ? '' : ($_SERVER["HTTPS"] == "on") ? "s" : "";
2066 $aProtocols = explode("/", strtolower($_SERVER["SERVER_PROTOCOL"]));
2067 $sProtocol = $aProtocols[0].$sSecure;
2068 $sPort = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]);
2069
2070 return $sProtocol."://".$_SERVER['SERVER_NAME'].$sPort.$sServerRequestUri;
2071 }
2072
2073 /**
2074 * Redirects the user to his destination.
2075 *
2076 * @param object $oObject The current object we want to access.
2077 *
2078 * @return null
2079 */
2080 public function redirectUser($oObject = null)
2081 {
2082 global $wp_query;
2083
2084 $blPostToShow = false;
2085 $aPosts = $wp_query->get_posts();
2086
2087 if ($oObject === null && isset($aPosts)) {
2088 foreach ($aPosts as $oPost) {
2089 if ($this->getAccessHandler()->checkObjectAccess($oPost->post_type, $oPost->ID)) {
2090 $blPostToShow = true;
2091 break;
2092 }
2093 }
2094 }
2095
2096 if (!$blPostToShow) {
2097 $aUamOptions = $this->getAdminOptions();
2098 $sPermalink = null;
2099
2100 if ($aUamOptions['redirect'] == 'custom_page') {
2101 $oPost = $this->getPost($aUamOptions['redirect_custom_page']);
2102 $sUrl = $oPost->guid;
2103 $sPermalink = get_page_link($oPost);
2104 } elseif ($aUamOptions['redirect'] == 'custom_url') {
2105 $sUrl = $aUamOptions['redirect_custom_url'];
2106 } else {
2107 $sUrl = home_url('/');
2108 }
2109
2110 if ($sUrl != $this->getCurrentUrl() && $sPermalink != $this->getCurrentUrl()) {
2111 wp_redirect($sUrl);
2112 exit;
2113 }
2114 }
2115 }
2116
2117 /**
2118 * Delivers the content of the requested file.
2119 *
2120 * @param string $sObjectType The type of the requested file.
2121 * @param string $sObjectUrl The file url.
2122 *
2123 * @return null
2124 */
2125 public function getFile($sObjectType, $sObjectUrl)
2126 {
2127 $oObject = $this->_getFileSettingsByType($sObjectType, $sObjectUrl);
2128
2129 if ($oObject === null) {
2130 return null;
2131 }
2132
2133 $sFile = null;
2134
2135 if ($this->getAccessHandler()->checkObjectAccess($oObject->type, $oObject->id)) {
2136 $sFile = $oObject->file;
2137 } elseif ($oObject->isImage) {
2138 $sFile = UAM_REALPATH.'gfx/noAccessPic.png';
2139 } else {
2140 wp_die(TXT_UAM_NO_RIGHTS);
2141 }
2142
2143 //Deliver content
2144 if (file_exists($sFile)) {
2145 $sFileName = basename($sFile);
2146
2147 /*
2148 * This only for compatibility
2149 * mime_content_type has been deprecated as the PECL extension file info
2150 * provides the same functionality (and more) in a much cleaner way.
2151 */
2152 $sFileExt = strtolower(array_pop(explode('.', $sFileName)));
2153 $aMimeTypes = $this->_getMimeTypes();
2154
2155 if (function_exists('finfo_open')) {
2156 $sFileInfo = finfo_open(FILEINFO_MIME);
2157 $sFileMimeType = finfo_file($sFileInfo, $sFile);
2158 finfo_close($sFileInfo);
2159 } elseif (function_exists('mime_content_type')) {
2160 $sFileMimeType = mime_content_type($sFile);
2161 } elseif (isset($aMimeTypes[$sFileExt])) {
2162 $sFileMimeType = $aMimeTypes[$sFileExt];
2163 } else {
2164 $sFileMimeType = 'application/octet-stream';
2165 }
2166
2167 header('Content-Description: File Transfer');
2168 header('Content-Type: '.$sFileMimeType);
2169
2170 if (!$oObject->isImage) {
2171 $sBaseName = str_replace(' ', '_', basename($sFile));
2172 header('Content-Disposition: attachment; filename="'.$sBaseName.'"');
2173 }
2174
2175 header('Content-Transfer-Encoding: binary');
2176 header('Content-Length: '.filesize($sFile));
2177
2178 $aUamOptions = $this->getAdminOptions();
2179
2180 if ($aUamOptions['download_type'] == 'fopen'
2181 && !$oObject->isImage
2182 ) {
2183 $oHandler = fopen($sFile, 'r');
2184
2185 //TODO find better solution (prevent '\n' / '0A')
2186 ob_clean();
2187 flush();
2188
2189 while (!feof($oHandler)) {
2190 if (!ini_get('safe_mode')) {
2191 set_time_limit(30);
2192 }
2193
2194 echo fread($oHandler, 1024);
2195 }
2196
2197 exit;
2198 } else {
2199 ob_clean();
2200 flush();
2201 readfile($sFile);
2202 exit;
2203 }
2204 } else {
2205 wp_die(TXT_UAM_FILE_NOT_FOUND_ERROR);
2206 }
2207 }
2208
2209 /**
2210 * Returns the file object by the given type and url.
2211 *
2212 * @param string $sObjectType The type of the requested file.
2213 * @param string $sObjectUrl The file url.
2214 *
2215 * @return object|null
2216 */
2217 protected function _getFileSettingsByType($sObjectType, $sObjectUrl)
2218 {
2219 $oObject = null;
2220
2221 if ($sObjectType == 'attachment') {
2222 $aUploadDir = wp_upload_dir();
2223
2224 $sMultiPath = str_replace(ABSPATH, '/', $aUploadDir['basedir']);
2225 $sMultiPath = str_replace('/files', $sMultiPath, $aUploadDir['baseurl']);
2226
2227 if ($this->isPermalinksActive()) {
2228 $sObjectUrl = $sMultiPath.'/'.$sObjectUrl;
2229 }
2230
2231 $oPost = $this->getPost($this->getPostIdByUrl($sObjectUrl));
2232
2233 if ($oPost !== null
2234 && $oPost->post_type == 'attachment'
2235 ) {
2236 $oObject = new stdClass();
2237 $oObject->id = $oPost->ID;
2238 $oObject->isImage = wp_attachment_is_image($oPost->ID);
2239 $oObject->type = $sObjectType;
2240 $oObject->file = $aUploadDir['basedir'].str_replace($sMultiPath, '', $sObjectUrl );
2241 }
2242 } else {
2243 $aPlObject = $this->getAccessHandler()->getPlObject($sObjectType);
2244
2245 if (isset($aPlObject) && isset($aPlObject['getFileObject'])) {
2246 $oObject = $aPlObject['reference']->{$aPlObject['getFileObject']}($sObjectUrl);
2247 }
2248 }
2249
2250 return $oObject;
2251 }
2252
2253 /**
2254 * Returns the url for a locked file.
2255 *
2256 * @param string $sUrl The base url.
2257 * @param integer $iId The _iId of the file.
2258 *
2259 * @return string
2260 */
2261 public function getFileUrl($sUrl, $iId)
2262 {
2263 $aUamOptions = $this->getAdminOptions();
2264
2265 if (!$this->isPermalinksActive() && $aUamOptions['lock_file'] == 'true') {
2266 $oPost = &$this->getPost($iId);
2267 $aType = explode("/", $oPost->post_mime_type);
2268 $sType = $aType[1];
2269 $aFileTypes = explode(',', $aUamOptions['locked_file_types']);
2270
2271 if ($aUamOptions['lock_file_types'] == 'all' || in_array($sType, $aFileTypes)) {
2272 $sUrl = home_url('/').'?uamfiletype=attachment&uamgetfile='.$sUrl;
2273 }
2274 }
2275
2276 return $sUrl;
2277 }
2278
2279 /**
2280 * Returns the post by the given url.
2281 *
2282 * @param string $sUrl The url of the post(attachment).
2283 *
2284 * @return object The post.
2285 */
2286 public function getPostIdByUrl($sUrl)
2287 {
2288 if (isset($this->_aPostUrls[$sUrl])) {
2289 return $this->_aPostUrls[$sUrl];
2290 }
2291
2292 $this->_aPostUrls[$sUrl] = null;
2293
2294 //Filter edit string
2295 $sNewUrl = preg_split("/-e[0-9]{1,}/", $sUrl);
2296
2297 if (count($sNewUrl) == 2) {
2298 $sNewUrl = $sNewUrl[0].$sNewUrl[1];
2299 } else {
2300 $sNewUrl = $sNewUrl[0];
2301 }
2302
2303 //Filter size
2304 $sNewUrl = preg_split("/-[0-9]{1,}x[0-9]{1,}/", $sNewUrl);
2305
2306 if (count($sNewUrl) == 2) {
2307 $sNewUrl = $sNewUrl[0].$sNewUrl[1];
2308 } else {
2309 $sNewUrl = $sNewUrl[0];
2310 }
2311
2312 /**
2313 * @var wpdb $wpdb
2314 */
2315 global $wpdb;
2316
2317 $sSql = $wpdb->prepare(
2318 "SELECT ID
2319 FROM ".$wpdb->prefix."posts
2320 WHERE guid = %s
2321 LIMIT 1",
2322 $sNewUrl
2323 );
2324
2325 $oDbPost = $wpdb->get_row($sSql);
2326
2327 if ($oDbPost) {
2328 $this->_aPostUrls[$sUrl] = $oDbPost->ID;
2329 }
2330
2331 return $this->_aPostUrls[$sUrl];
2332 }
2333
2334 /**
2335 * Caches the urls for the post for a later lookup.
2336 *
2337 * @param string $sUrl The url of the post.
2338 * @param object $oPost The post object.
2339 *
2340 * @return null
2341 */
2342 public function cachePostLinks($sUrl, $oPost)
2343 {
2344 $this->_aPostUrls[$sUrl] = $oPost->ID;
2345 return $sUrl;
2346 }
2347 }