Advertisement
MaxPovver

TryLoadDocument

Oct 23rd, 2014
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 22.45 KB | None | 0 0
  1. <?php
  2. //Сниппет TryLoadDocument
  3. /**
  4. Итак, все документы хранятся в базе вот в таком виде(переделано в формат JSON для лучшей читаемости):
  5. {
  6. "type":"agreement", - тип документа, текстовый, короткий, примеры: carta, license и т.д.
  7. "title":"Договор", - заголовок документа
  8. "text":"Пример. Текст договора. Подпишите здесь: ______ ", - текст документа, XSS контролирует CLeditor, не наша забота. Содержит весь текст какого-то документа со всеми тегами разметки.
  9. "owner":29, - это владелец документа, то есть тот, с кем наш сайт его заключил. у него в любом случае есть право смотреть  и редактировать этот документ(т.к. он "его")
  10. "edit":[29,555,34,52], - это те, кто может редактировать документ.
  11. !ВАЖНО! пользователи групп  Administrator,Jurists имеют доступ к ЛЮБОМУ документу!
  12. "view":[5677,599677,5999898677,855677] - те, кто открыв страничку http://.../docs?doc_id=5 увидят этот документ(но редактировать не смогут)
  13. "view-temp":[{"id":5,"until":1413640050},{"id":9,"until":1413640100},{"id":7,"until":1413640050}] - аналогично view, но "until"(формат timestamp) указывает, вплоть до какого момента времени нужно учитывать эту запись(после этого момента она удаляется)
  14. "edit-temp":[{"id":5,"until":1413640050},{"id":9,"until":1413640100},{"id":7,"until":1413640050}] - аналогично edit, но "until"(формат timestamp) указывает, вплоть до какого момента времени нужно учитывать эту запись(после этого момента она удаляется)
  15. }
  16. вот таким запросом можно такую таблицу создать:
  17. CREATE TABLE IF NOT EXISTS `documents` (
  18.   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id документа',
  19.   `type` varchar(255) NOT NULL COMMENT 'тип документа',
  20.   `title` varchar(255) NOT NULL COMMENT 'заголовок документа',
  21.   `text` text NOT NULL COMMENT 'текст документа',
  22.   `owner` bigint(20) NOT NULL COMMENT 'владелец дока',
  23.   `edit` text NOT NULL COMMENT 'все юзеры, у кого есть права на просмотр и редактирование',
  24.   `edit-temp` text NOT NULL COMMENT 'временные разрешения на редактирование',
  25.   `view` text NOT NULL COMMENT 'все юзеры, у кого есть права на просмотр',
  26.   `view-temp` text NOT NULL COMMENT 'временные разрешения на редактирование',
  27.   UNIQUE KEY `id` (`id`)
  28. ) ENGINE=InnoDB  DEFAULT CHARSET=cp1251 COMMENT='Личные документы пользователей - здесь...';
  29. */
  30.  
  31. class Document {
  32.     private $data;//здесь все данные документа в виде ассоциативного массива(напр $data['title'] - заголовок документа)
  33.     private $uid;//=user id — id того, кто пытается использовать этот документ(или создать)
  34.     private $modx;//для работы с modx API
  35.    public function  __construct($modx)
  36.     {//т.к. доступа напрямую к $modx в функциях нет(по крайней мере у меня), передадим ее параметром
  37.         $this->modx=$modx;
  38.         $this->uid=$this->modx->user->get('id');//объект документа можно создать только от имени текущего юзера
  39.     }
  40. public function &__set (  $name ,  $value )
  41.     {//снаружи(не используя функций) менять можно только title и text
  42.        $allowed=["title","text"];
  43.        if(in_array($name,$allowed))
  44.        {
  45.           if($this->editAllowed())//если текущему пользователю можно редактировать
  46.             $this->data[$name]=$value;
  47.        }
  48.     }
  49.     public function &__get (  $name )
  50.     {//снаружи класса напрямую получить значения полей могут все из списков edit & view, а также владелец...
  51.         if($this->isOwner() || $this->viewAllowed() || $this->editAllowed())
  52.         {
  53.         switch ($name)
  54.         {
  55.             case "title":return $this->data['title'];
  56.             case "text": return $this->data['text'];
  57.             case "id": return $this->data['id'];
  58.             case "uid": return $this->uid;
  59.         }
  60.         }
  61.         return 'forbidden';
  62.     }
  63. public function MakeNew($type,$title,$text)//для создания документа по шаблону, либо сгенерированного динамически
  64.     {
  65.         $this->data['text']=$text;//текст документа
  66.         $this->data['title']=$title;//заголовок
  67.         $this->data['view']=[];//кому можно просматривать документ
  68.         $this->data['view-temp']=[];
  69.         $this->data['edit']=[];//кому можно документ редактировать
  70.         $this->data['edit-temp']=[];
  71.  
  72.         $this->load($this->saveAsNew($type));//сохраняем док и загружаем его в нормальном виде
  73.     }
  74.     public function viewAllowed()
  75.     {//возвращает истину, если этому юзеру можно просматривать этот документ, иначе - ложь..
  76.         $allowed= $this->isOwner()//если запрашивающий - создатель документа
  77.         || in_array($this->uid,$this->data['view']);//или имеет право на его просмотр
  78.         if($allowed)
  79.             return true;
  80.         else
  81.             for($i=0; $i<count($this->data['view-temp']);$i++)
  82.                 if($this->data['view-temp'][$i]->id==$this->uid)
  83.                     return $this->data['view-temp'][$i]->until > time();
  84.         return false;
  85.     }
  86.     public function editAllowed()
  87.     {//возвращает истину, если этому юзеру можно редактировать этот документ, иначе - ложь..
  88.         $allowed = $this->isOwner() || //если запрашивающий - создатель документа
  89.         in_array($this->uid,$this->data['edit']);//если запрашивающему можно редактировать документ
  90.         if($allowed)
  91.             return true;
  92.         else
  93.             for($i=0; $i<count($this->data['edit-temp']);$i++)
  94.                 if($this->data['edit-temp'][$i]->id==$this->uid)
  95.                     return $this->data['edit-temp'][$i]->until > time();
  96. //доступ к временным полям через '->' из-за принципа декодирования функцией json_decode
  97.         return false;
  98.     }
  99.     public function manageAllowed()
  100.     {//true если этому юзеру можно давать другим доступ к документу. false в обратном случае.
  101.         return $this->modx->user->isMember('Jurists')||$this->modx->user->isMember('Administrator');
  102.     }
  103.     public function allow($new_user,$can_edit,$time=0)
  104.     {
  105.         //дать кому-то доступ к документу. $new_user - кому дать,  
  106.     //$can_edit - может ли редактировать(только если запросивший сам может редактировать, иначе не сработает)
  107.     //$time - на какое время дать права(по умолчанию 0 - навсегда. измеряется в секундах
  108.         $user_id=(int)$new_user;
  109.         if($user_id!=0 && $this->manageAllowed())
  110.             if($can_edit)
  111.             {
  112.             if($this->editAllowed())
  113.                 {
  114.                         if($time==0)//выдать права навсегда
  115.                             $this->data['edit'][]=$user_id;
  116.                         else//выдать права на $time секунд
  117.                             $this->data['edit-temp'][]=["id"=>$user_id,"until"=>time()+$time];
  118.                 }
  119.             }
  120.             else
  121.             {
  122.                         if($time==0)//выдать права навсегда
  123.                             $this->data['view'][]=$user_id;
  124.                         else//выдать права на $time секунд
  125.                             $this->data['view-temp'][]=["id"=>$user_id,"until"=>time()+$time];
  126.             }
  127.     }
  128.     public function isOwner()
  129.     {
  130.        $usual=$this->uid==$this->data['owner'];//права владельца есть у:
  131.        if($usual) return true;//самого владельца,
  132.        else//спец аккаунтов
  133.        return $this->manageAllowed();
  134.     }
  135.  
  136. Вспомогательная функция, очищающая документ от устаревших временных разрешений
  137.     private function clearTemp()
  138.     {//очищает все массивы от врeменных разрешений у которых прошел срок действия
  139.       if(count($this->data['view-temp'])+count($this->data['edit-temp']) > 0)//если хоть какие-то временные данные есть
  140.       {
  141.         for($i=0; $i<count($this->data['view-temp']);$i++)
  142. //удалить все временные разрешения, у которых дата истечения раньше текущего времени(time())
  143.         {
  144.             if($this->data['view-temp'][$i]->until < time())
  145.                 unset($this->data['view-temp'][$i]);
  146.         }
  147.         $this->data['view-temp']=array_values($this->data['view-temp']);//просто фикс проблемы с индексами( [1,3,5]=>[0,1,2)]
  148.  
  149.         for($i=0; $i<count($this->data['edit-temp']);$i++)
  150. //удалить все временные разрешения, у которых дата истечения раньше текущего времени(time())
  151.         {
  152.             if($this->data['edit-temp'][$i]->until < time())
  153.                 unset($this->data['edit-temp'][$i]);
  154.         }
  155.         $this->data['edit-temp'] = array_values($this->data['edit-temp']);//просто фикс проблемы с индексами( [1,3,5]=>[0,1,2)]
  156.  
  157.         $this->save();//сохранить изменения
  158.  
  159.         }
  160.     }
  161.     public function load($id)
  162.     {//загружает документ из бд(на это прав хватит у любого, вот только не любой сможет эти данные у класса получить)
  163.         $sql="SELECT * FROM `documents` WHERE `id`=:id";
  164.         $query = new xPDOCriteria($this->modx, $sql,array(':id'=>$id));
  165.         if($query->prepare() && $query->stmt->execute())
  166.         {//если данные удачно загружены
  167.             $this->data = $query->stmt->fetchAll(PDO::FETCH_ASSOC)[0];
  168.             if(count($this->data)==0) return false;//если пришел пустой ответ, сообщаем о фейле зуагрузки
  169.             $this->data['edit']=json_decode($this->data['edit']);///распаковываем список имеющих право на редактирование в массив
  170.             $this->data['edit-temp']=json_decode($this->data['edit-temp']);///распаковываем список имеющих временное право на редактирование в массив
  171.             $this->data['view']=json_decode($this->data['view']);///распаковываем список имеющих право на просмотр в массив
  172.             $this->data['view-temp']=json_decode($this->data['view-temp']);///распаковываем список имеющих временное право на просмотр в массив
  173.             $this->clearTemp();//очищаем массивы view-temp & edit-temp от закончившихся разрешений
  174.             return true;//раз дошли сюда, сообщаем, что все ок
  175.         }
  176.         else  return false;//если не выполнился запрос, сообщаем о фейле загрузки
  177.     }
  178.  
  179.     public function save()
  180.     {//сохраняет новое значение документа в бд
  181.         $sql="UPDATE `documents` SET `title`=:title, `text`=:text, `view`=:view, `edit`=:edit, `view-temp`=:viewtemp, `edit-temp`=:edittemp WHERE `id`=:id";//шаблон запроса
  182.         $this->data['view']=json_encode($this->data['view']);///запаковываем список имеющих право на просмотр в строку
  183.         $this->data['view-temp']=json_encode($this->data['view-temp']);///запаковываем список имеющих право на временный просмотр в строку
  184.         $this->data['edit']=json_encode($this->data['edit']);///запаковываем список имеющих право на редактирование в строку
  185.         $this->data['edit-temp']=json_encode($this->data['edit-temp']);///запаковываем список имеющих право на временное редактирование в строку
  186.         $query=new xPDOCriteria($this->modx, $sql,
  187.         [":title"=>$this->data['title'],":text"=>$this->data['text'],":edit"=>$this->data['edit'],":view"=>$this->data['view'],":edittemp"=>$this->data['edit-temp'],":viewtemp"=>$this->data['view-temp'],":id"=>$this->data["id"]]);//подставляем данные
  188.  
  189.         $query->prepare() && $query->stmt->execute();//выполняем запрос
  190.         //преобразуем строки обратно в массивы
  191.         $this->data['view']=json_decode($this->data['view']);
  192.         $this->data['view-temp']=json_decode($this->data['view-temp']);
  193.         $this->data['edit']=json_decode($this->data['edit']);
  194.         $this->data['edit-temp']=json_decode($this->data['edit-temp']);
  195.  
  196.     }
  197.     private function saveAsNew($type)
  198.     {//сохраняет уже заполненный документ как новую запись типа $type
  199.         $sql="INSERT INTO `documents` (`title`,`text`,`view`,`edit`,`owner`,`type`) VALUES(:title,:text,:view,:edit,:uid,:type)";//шаблон запроса
  200.         $this->data['view']=json_encode($this->data['view']);///запаковываем список имеющих право на просмотр в строку
  201.         $this->data['edit']=json_encode($this->data['edit']);///запаковываем список имеющих право на редактирование в строку
  202.         $this->data['view-temp']=json_encode($this->data['view-temp']);///запаковываем список имеющих право на просмотр в строку
  203.         $this->data['edit-temp']=json_encode($this->data['edit-temp']);///запаковываем список имеющих право на редактирование в строку
  204.         $query=new xPDOCriteria($this->modx, $sql,
  205.         [":title"=>$this->data['title'],":text"=>$this->data['text'],":edit"=>$this->data['edit'],":view"=>$this->data['view'],":uid"=>$this->uid,":type"=>$type]);//подставляем данные
  206.                 //логгируем создание нового документа, полезно для отладки и чтобы посмотреть как шаблон данными заполняется
  207.         //$this->modx->log(modX::LOG_LEVEL_ERROR,"Выполнение запроса: ".$query->toSQL());
  208.  
  209.         $query->prepare(); $query->stmt->execute();//выполняем запрос
  210.  
  211.         return $this->modx->lastInsertId();//вернем id созданного дока
  212.     }
  213. }
  214. if(DOC_API_MODE!="API")//если нужен только класс Document, эта часть кода не выполнится)
  215. {
  216.    if($modx->user->get('id')==0)//если на страницу зашел анон,
  217. {
  218.    $modx->sendRedirect($modx->makeUrl(14));//отправляем его на страницу номер 14, именно там у нас вход в систему.
  219.    exit;//на случай если редирект ВДРУГ не сработал, завершаем скрипт наверняка(вместо странчики будет просто белый экран)
  220. }
  221. /*******/
  222.  
  223. $doc=new Document($modx);//создаем объект для работы с документом для вошедшего на страницу пользователя
  224. if(!$doc->load($_GET['doc_id']))//пытаемся загрузить док из бд
  225. {//если не удалось, выходим...
  226.     return 'Документ не найден...';
  227. }
  228. //!!! сообщаем чанку Rights, отображать ли поле редактирования доступом
  229. $modx->setPlaceholder('CanManage',$doc->manageAllowed()?'true':'false');
  230. //!!! сообщаем чанку DocText, отображать ли форму редактирования
  231. $modx->setPlaceholder('CanEdit',$doc->editAllowed()?'true':'false');
  232.  
  233. function DataToUID($userstr,$modx)//для вытаскивания цифры с номером пользователя из поля "пользователю"
  234. {
  235.     $link_rgx="/(.*uid=)([\d]{1,})(.*)/";//регулярка для ссылки вида http://*путь до личного кабинета*?uid=56
  236.     $id_rgx="/([^\w]{0,})([\d]{1,})/";//регулярка id пользователя(до и после числа могут быть пробелы)
  237.     if(preg_match($link_rgx,$userstr))
  238.     {//для ссылки вида http://*путь до личного кабинета*?uid=56
  239.         $r="$2";
  240.         return preg_replace($link_rgx,$r,$userstr);
  241.     } else
  242.     if(preg_match($id_rgx,$userstr))//если ввод был "  234", например
  243.     {
  244.         $r="$2";
  245.         return preg_replace($id_rgx,$r,$userstr);//вернем только число
  246.     } else//это и не идентификатор юзера и не ссылка на его лк? тогда может это ник?
  247.     {
  248.         $usr=$modx->getObject('modUser',["username"=>$userstr]);//пытаемся найти юзера с таким ником
  249.         return  $usr?$usr->get('id'):'-1';
  250.     }
  251.  
  252. }
  253. /*********Эти два для работы в режиме форм***********/
  254. if(isset($_POST['add']))//если юзер нажал кнопочку "добавить права пользователю...
  255. {
  256.     $userID=(int)DataToUID($_POST['userid'],$modx);//вытаскиваем id пользователя из поля формы 'userid'
  257.     if($userID!='-1')//если пользователь нашелся
  258.     {
  259.  
  260.          if($_POST['allow']=="edit")//если надо добавить права на редактирование и просмотр(задается полем формы 'allow')
  261.          {
  262. //пишем в лог
  263.             $modx->log(modX::LOG_LEVEL_ERROR,"Попытка выдать права на редактирование документа #".$doc->id." пользователем #".$doc->uid." пользователю #".$userID);
  264.             $doc->allow($userID,true,(int)$_POST['length']);
  265.             $doc->save();
  266.          } else
  267.          if($_POST['allow']=="view")////если надо добавить права на просмотр(задается полем формы 'allow')
  268.          {
  269. //пишем в лог
  270.             $modx->log(modX::LOG_LEVEL_ERROR,"Попытка выдать права на просмотр документа #".$doc->id." пользователем #".$doc->uid." пользователю #".$userID);
  271.             $doc->allow($userID,false,(int)$_POST['length']);
  272.             $doc->save();
  273.          }
  274.     }else $modx->log(modX::LOG_LEVEL_ERROR,"DataToUID не справилась. (".$_POST['userid'].")");//если вместо имени пользователя передали фигню, пишем в лог
  275. }
  276.  
  277. if(isset($_POST['edit']))//если юзер отредактировал документ и нажал "сохранить"
  278. {
  279.     $modx->log(modX::LOG_LEVEL_ERROR,"Попытка отредактировать текст документа #".$doc->id." пользователем #".$doc->uid);//пишем в лог
  280.     if(!empty($_POST["text"]))//если новый вариант документа не пуст(нету смысла в пустых доках)
  281.         {
  282.             $doc->text=$_POST["text"];//задаем полю класса text новое значение
  283.             $doc->save();
  284.             $modx->log(modX::LOG_LEVEL_ERROR,"Отредактирован текст документа #".$doc->id." пользователем #".$doc->uid);//пишем в лог
  285.         }
  286. }
  287.  
  288. /**********Вывод данных в форму*************/
  289. if(!isset($_POST['ajax']))//если мы вызваны не через аякс, а для загрузки страницы.
  290. {
  291.     $output="";
  292.     //грузим док, если нельзя, то объект сам разберется
  293. //передаем чанку заголовка DocTitle параметром свойство title, то есть заголовок документа. проверять доступ к нему - не наша забота.
  294.     $output.=$modx->getChunk('DocTitle',['title'=>$doc->title]);
  295. //передаем чанку заголовка DocText параметром свойство title, то есть заголовок документа. проверять доступ к нему - не наша забота.
  296.     $output.=$modx->getChunk('DocText',['text'=>$doc->text]);
  297.     $modx->setPlaceholder('doc', $output);
  298.     return '';
  299. }
  300.  
  301. return 'Ошибка...';//для нормального кода мы здесь вообще не должны оказаться, так что вернем хоть что-то для объяснения неполадки
  302. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement