PageRenderTime 29ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/system/PageLock/lib/PageLock/Api/User.php

https://github.com/ThiloWitt/core
PHP | 225 lines | 149 code | 53 blank | 23 comment | 19 complexity | 65463721a8a5ecb35aec6fb4a97e2825 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright Zikula Foundation 2009 - Zikula Application Framework
  4. *
  5. * This work is contributed to the Zikula Foundation under one or more
  6. * Contributor Agreements and licensed to You under the following license:
  7. *
  8. * @license GNU/LGPLv3 (or at your option, any later version).
  9. * @package Zikula
  10. *
  11. * Please see the NOTICE file distributed with this source code for further
  12. * information regarding copyright and licensing.
  13. */
  14. /**
  15. * length of time to lock a page
  16. *
  17. */
  18. define('PageLockLifetime', 30);
  19. class PageLock_Api_User extends Zikula_AbstractApi
  20. {
  21. public function pageLock($args)
  22. {
  23. $lockName = $args['lockName'];
  24. $returnUrl = (array_key_exists('returnUrl', $args) ? $args['returnUrl'] : null);
  25. $ignoreEmptyLock = (array_key_exists('ignoreEmptyLock', $args) ? $args['ignoreEmptyLock'] : false);
  26. $uname = UserUtil::getVar('uname');
  27. $lockedHtml = '';
  28. if (!empty($lockName) || !$ignoreEmptyLock) {
  29. PageUtil::AddVar('javascript', 'zikula.ui');
  30. PageUtil::AddVar('javascript', 'system/PageLock/javascript/pagelock.js');
  31. PageUtil::AddVar('stylesheet', ThemeUtil::getModuleStylesheet('pagelock'));
  32. $lockInfo = ModUtil::apiFunc('pagelock', 'user', 'requireLock',
  33. array('lockName' => $lockName,
  34. 'lockedByTitle' => $uname,
  35. 'lockedByIPNo' => $_SERVER['REMOTE_ADDR']));
  36. $hasLock = $lockInfo['hasLock'];
  37. if (!$hasLock) {
  38. $view = Zikula_View::getInstance('pagelock');
  39. $view->assign('lockedBy', $lockInfo['lockedBy']);
  40. $lockedHtml = $view->fetch('PageLock_lockedwindow.tpl');
  41. }
  42. } else {
  43. $hasLock = true;
  44. }
  45. $html = "<script type=\"text/javascript\">\n";
  46. if (!empty($lockName)) {
  47. if ($hasLock) {
  48. $html .= "document.observe('dom:loaded', PageLock.UnlockedPage);\n";
  49. } else {
  50. $html .= "document.observe('dom:loaded', PageLock.LockedPage);\n";
  51. }
  52. }
  53. $lockedHtml = str_replace("\n", "", $lockedHtml);
  54. $lockedHtml = str_replace("\r", "", $lockedHtml);
  55. // Use "PageLockLifetime*2/3" to add a good margin to lock timeout when pinging
  56. // disabled due to #2556 and #2745
  57. // $returnUrl = DataUtil::formatForDisplayHTML($returnUrl);
  58. $html .= "
  59. PageLock.LockName = '$lockName';
  60. PageLock.ReturnUrl = '$returnUrl';
  61. PageLock.PingTime = " . (PageLockLifetime*2/3) . ";
  62. PageLock.LockedHTML = '" . $lockedHtml . "';
  63. </script>";
  64. PageUtil::addVar('header', $html);
  65. return true;
  66. }
  67. public function requireLock($args)
  68. {
  69. $lockName = $args['lockName'];
  70. $sessionId = (array_key_exists('sessionId', $args) ? $args['sessionId'] : session_id());
  71. $lockedByTitle = $args['lockedByTitle'];
  72. $lockedByIPNo = $args['lockedByIPNo'];
  73. $this->_pageLockRequireAccess();
  74. $locks = ModUtil::apiFunc('pagelock', 'user', 'getLocks', $args);
  75. if (count($locks) > 0) {
  76. $lockedBy = '';
  77. foreach ($locks as $lock) {
  78. if (strlen($lockedBy) > 0) {
  79. $lockedBy .= ', ';
  80. }
  81. $lockedBy .= $lock['lockedByTitle'] . " ($lock[lockedByIPNo]) " . $lock['createdDate'];
  82. }
  83. return array('hasLock' => false, 'lockedBy' => $lockedBy);
  84. }
  85. $args['lockedBy'] = null;
  86. $dbtable = DBUtil::getTables();
  87. $pageLockTable = &$dbtable['pagelock'];
  88. $pageLockColumn = &$dbtable['pagelock_column'];
  89. // Look for existing lock
  90. $sql = "
  91. SELECT COUNT(*)
  92. FROM $pageLockTable
  93. WHERE $pageLockColumn[name] = '" . DataUtil::formatForStore($lockName) . "' AND $pageLockColumn[lockedBySessionId] = '" . DataUtil::formatForStore($sessionId) . "'";
  94. $count = DBUtil::selectScalar($sql);
  95. $now = time();
  96. $expireDate = $now + PageLockLifetime;
  97. if ($count > 0) {
  98. // Update existing lock
  99. $sql = "
  100. UPDATE $pageLockTable
  101. SET $pageLockColumn[expiresDate] = '" . DateUtil::getDatetime($expireDate) . "'
  102. WHERE $pageLockColumn[name] = '" . DataUtil::formatForStore($lockName) . "' AND $pageLockColumn[lockedBySessionId] = '" . DataUtil::formatForStore($sessionId) . "'";
  103. DBUtil::executeSql($sql);
  104. } else {
  105. $data = array('name' => $lockName,
  106. 'createdDate' => DateUtil::getDatetime($now),
  107. 'expiresDate' => DateUtil::getDatetime($expireDate),
  108. 'lockedBySessionId' => $sessionId,
  109. 'lockedByTitle' => $lockedByTitle,
  110. 'lockedByIPNo' => $lockedByIPNo);
  111. DBUtil::insertObject($data, 'pagelock');
  112. }
  113. $this->_pageLockReleaseAccess();
  114. return array('hasLock' => true);
  115. }
  116. public function getLocks($args)
  117. {
  118. $lockName = $args['lockName'];
  119. $sessionId = (array_key_exists('sessionId', $args) ? $args['sessionId'] : session_id());
  120. $this->_pageLockRequireAccess();
  121. $dbtable = DBUtil::getTables();
  122. $pageLockColumn = &$dbtable['pagelock_column'];
  123. $now = time();
  124. $where = "{$pageLockColumn['expiresDate']} < '" . DateUtil::getDatetime($now) . "'";
  125. DBUtil::deleteWhere('pagelock', $where);
  126. $where = "{$pageLockColumn['name']} = '" . DataUtil::formatForStore($lockName) . "' AND {$pageLockColumn['lockedBySessionId']} != '" . DataUtil::formatForStore($sessionId) . "'";
  127. $locks = DBUtil::selectObjectArray('pagelock', $where);
  128. $this->_pageLockReleaseAccess();
  129. return $locks;
  130. }
  131. public function releaseLock($args)
  132. {
  133. $lockName = $args['lockName'];
  134. $sessionId = (array_key_exists('sessionId', $args) ? $args['sessionId'] : session_id());
  135. $this->_pageLockRequireAccess();
  136. $dbtable = DBUtil::getTables();
  137. $pageLockTable = &$dbtable['pagelock'];
  138. $pageLockColumn = &$dbtable['pagelock_column'];
  139. $sql = "DELETE FROM $pageLockTable WHERE $pageLockColumn[name] = '" . DataUtil::formatForStore($lockName) . "' AND $pageLockColumn[lockedBySessionId] = '" . DataUtil::formatForStore($sessionId) . "'";
  140. DBUtil::executeSql($sql);
  141. $this->_pageLockReleaseAccess();
  142. return true;
  143. }
  144. // Internal locking mechanism to avoid concurrency inside the PageLock functions
  145. private function _pageLockRequireAccess()
  146. {
  147. global $PageLockAccessCount;
  148. if ($PageLockAccessCount == null) {
  149. $PageLockAccessCount = 0;
  150. }
  151. if ($PageLockAccessCount == 0) {
  152. global $PageLockFile;
  153. $ostemp = DataUtil::formatForOS(System::getVar('temp'), true);
  154. $PageLockFile = fopen($ostemp . '/pagelock.lock', "w+");
  155. flock($PageLockFile, LOCK_EX);
  156. fwrite($PageLockFile, "This is a locking file for synchronizing access to the PageLock module. Please do not delete.");
  157. fflush($PageLockFile);
  158. }
  159. ++$PageLockAccessCount;
  160. }
  161. // Internal locking mechanism to avoid concurrency inside the PageLock functions
  162. private function _pageLockReleaseAccess()
  163. {
  164. global $PageLockAccessCount;
  165. --$PageLockAccessCount;
  166. if ($PageLockAccessCount == 0) {
  167. global $PageLockFile;
  168. flock($PageLockFile, LOCK_UN);
  169. fclose($PageLockFile);
  170. }
  171. }
  172. }