Qurl.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. App::uses('ToolsAppModel', 'Tools.Model');
  3. /**
  4. * Manage Quick Urls
  5. *
  6. * @author Mark Scherer
  7. * @cakephp 2.x
  8. * @license MIT
  9. * 2012-05-21 ms
  10. */
  11. class Qurl extends ToolsAppModel {
  12. public $displayField = 'key';
  13. public $scaffoldSkipFields = array('note', 'key', 'content');
  14. public $order = array('Qurl.created' => 'DESC');
  15. protected $defaultLength = 22;
  16. protected $validity = YEAR;
  17. public $validate = array(
  18. 'key' => array(
  19. 'notEmpty' => array(
  20. 'rule' => array('notEmpty'),
  21. 'message' => 'valErrMandatoryField',
  22. 'last' => true,
  23. ),
  24. 'isUnique' => array(
  25. 'rule' => array('isUnique'),
  26. 'message' => 'valErrQurlKeyExists',
  27. ),
  28. ),
  29. 'url' => array(
  30. 'notEmpty' => array(
  31. 'rule' => array('notEmpty'),
  32. 'message' => 'valErrMandatoryField',
  33. 'last' => true
  34. ),
  35. 'validateUrl' => array(
  36. 'rule' => array('validateUrl', array('deep'=>false, 'sameDomain'=>true, 'autoComplete'=>true)),
  37. 'message' => 'valErrInvalidQurlUrl',
  38. 'last' => true
  39. )
  40. ),
  41. 'note' => array(
  42. ),
  43. 'comment' => array(
  44. ),
  45. 'used' => array(
  46. 'numeric' => array(
  47. 'rule' => array('numeric'),
  48. 'message' => 'valErrMandatoryField',
  49. ),
  50. ),
  51. );
  52. public function beforeValidate($options = array()) {
  53. parent::beforeValidate($options);
  54. if (isset($this->data[$this->alias]['key']) && empty($this->data[$this->alias]['key'])) {
  55. $length = null;
  56. if (!empty($this->data[$this->alias]['key_length'])) {
  57. $length = $this->data[$this->alias]['key_length'];
  58. }
  59. $this->data[$this->alias]['key'] = $this->generateKey($length);
  60. }
  61. return true;
  62. }
  63. public function beforeSave($options = array()) {
  64. parent::beforeSave($options);
  65. if (isset($this->data[$this->alias]['content'])) {
  66. $this->data[$this->alias]['content'] = serialize($this->data[$this->alias]['content']);
  67. }
  68. return true;
  69. }
  70. public function translate($key) {
  71. $res = $this->find('first', array('conditions'=>array($this->alias.'.key'=>$key, $this->alias.'.active'=>1)));
  72. if (!$res) {
  73. return false;
  74. }
  75. //$res['CodeKey']['url'] = Router::url($content['url'], true);
  76. if ($res[$this->alias]['content']) {
  77. $res[$this->alias]['content'] = unserialize($res[$this->alias]['content']);
  78. } else {
  79. $res[$this->alias]['content'] = array();
  80. }
  81. return $res;
  82. }
  83. /**
  84. * form the access url by key
  85. * @param string $key
  86. * @retur string $url (absolute)
  87. */
  88. public static function urlByKey($key, $title = null, $slugTitle = true) {
  89. if ($title && $slugTitle) {
  90. $title = Inflector::slug($title, '-');
  91. }
  92. return Router::url(array('admin' => false, 'plugin'=>'tools', 'controller'=>'qurls', 'action'=>'go', $key, $title), true);
  93. }
  94. /**
  95. * makes an absolute url string ready to input anywhere
  96. * uses generate() internally to get the key
  97. * @param mixed $url
  98. * @return string $url (absolute)
  99. */
  100. public function url($url, $data = array()) {
  101. $key = $this->generate($url, $data);
  102. if (!$key) {
  103. return false;
  104. }
  105. return $this->urlByKey($key);
  106. }
  107. /**
  108. * generates a Qurl key
  109. * @param mixed $url
  110. * @param string $uid
  111. * @return string $key
  112. * 2011-07-12 ms
  113. */
  114. public function generate($url, $data = array()) {
  115. $url = Router::url($url, true);
  116. $content = array_merge($data, array('url'=>$url));
  117. if (!isset($content['key'])) {
  118. $content['key'] = '';
  119. }
  120. $res = $this->save($content);
  121. if (!$res) {
  122. return false;
  123. }
  124. return $res[$this->alias]['key'];
  125. }
  126. /**
  127. * sets Key to "used" (only once!) - directly by ID
  128. * @param id of key to spend: necessary
  129. * @return boolean true on success, false otherwise
  130. * 2009-05-13 ms
  131. */
  132. public function markAsUsed($id = null) {
  133. if (empty($id)) {
  134. return false;
  135. }
  136. //$this->id = $id;
  137. if ($this->updateAll(array($this->alias.'.used' => $this->alias.'.used + 1', $this->alias.'.last_used'=>'"'.date(FORMAT_DB_DATETIME).'"'), array($this->alias.'.id'=>$id))) {
  138. return true;
  139. }
  140. return false;
  141. }
  142. /**
  143. * remove old/invalid keys
  144. * does not remove recently used ones (for proper feedback)!
  145. * @return boolean success
  146. * 2010-06-17 ms
  147. */
  148. public function garbigeCollector() {
  149. $conditions = array(
  150. $this->alias.'.created <'=>date(FORMAT_DB_DATETIME, time()-$this->validity),
  151. );
  152. return $this->deleteAll($conditions, false);
  153. }
  154. /**
  155. * get admin stats
  156. * 2010-10-22 ms
  157. */
  158. public function stats() {
  159. $keys = array();
  160. $keys['unused_valid'] = $this->find('count', array('conditions'=>array($this->alias.'.used'=>0, $this->alias.'.created >='=>date(FORMAT_DB_DATETIME, time()-$this->validity))));
  161. $keys['used_valid'] = $this->find('count', array('conditions'=>array($this->alias.'.used'=>1, $this->alias.'.created >='=>date(FORMAT_DB_DATETIME, time()-$this->validity))));
  162. $keys['unused_invalid'] = $this->find('count', array('conditions'=>array($this->alias.'.used'=>0, $this->alias.'.created <'=>date(FORMAT_DB_DATETIME, time()-$this->validity))));
  163. $keys['used_invalid'] = $this->find('count', array('conditions'=>array($this->alias.'.used'=>1, $this->alias.'.created <'=>date(FORMAT_DB_DATETIME, time()-$this->validity))));
  164. $urls = $this->find('all', array('conditions'=>array(), 'fields'=>array('DISTINCT url')));
  165. $keys['urls'] = !empty($urls) ? Set::extract('/'.$this->alias.'/url', $urls) : array();
  166. return $keys;
  167. }
  168. /**
  169. * @param length (defaults to defaultLength)
  170. * @return string codekey
  171. * 2009-05-13 ms
  172. */
  173. public function generateKey($length = null) {
  174. if (empty($length)) {
  175. $length = $this->defaultLength;
  176. }
  177. if ((class_exists('CommonComponent') || App::import('Component', 'Common')) && method_exists('CommonComponent', 'generatePassword')) {
  178. return CommonComponent::generatePassword($length);
  179. } else {
  180. return $this->_generateKey($length);
  181. }
  182. }
  183. /**
  184. * backup method - only used if no custom function exists
  185. * 2010-06-17 ms
  186. */
  187. protected function _generateKey($length = null) {
  188. $chars = "234567890abcdefghijkmnopqrstuvwxyz"; // ABCDEFGHIJKLMNOPQRSTUVWXYZ
  189. $i = 0;
  190. $password = "";
  191. $max = strlen($chars) - 1;
  192. while ($i < $length) {
  193. $password .= $chars[mt_rand(0, $max)];
  194. $i++;
  195. }
  196. return $password;
  197. }
  198. }