File indexing completed on 2024-07-14 05:42:47

0001 <?php
0002 /** @noinspection PhpStatementHasEmptyBodyInspection */
0003 /** @noinspection PhpUndefinedFieldInspection */
0004 /**
0005  *  ocs-apiserver
0006  *
0007  *  Copyright 2016 by pling GmbH.
0008  *
0009  *    This file is part of ocs-apiserver.
0010  *
0011  *    This program is free software: you can redistribute it and/or modify
0012  *    it under the terms of the GNU Affero General Public License as
0013  *    published by the Free Software Foundation, either version 3 of the
0014  *    License, or (at your option) any later version.
0015  *
0016  *    This program is distributed in the hope that it will be useful,
0017  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0018  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0019  *    GNU Affero General Public License for more details.
0020  *
0021  *    You should have received a copy of the GNU Affero General Public License
0022  *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0023  *
0024  * Created: 01.12.2017
0025  */
0026 
0027 /**
0028  * What changes from official OCS v1 spec
0029  *
0030  * OCS specification:
0031  * https://www.freedesktop.org/wiki/Specifications/open-collaboration-services/
0032  *
0033  * ----
0034  *
0035  * Allow delimiter ',' of value of parameter 'categories'
0036  *
0037  * Example:
0038  * /content/data?categories=1,2,3
0039  * /content/data?categories=1x2x3
0040  *
0041  * ----
0042  *
0043  * Additional URL queries to '/content/data'
0044  *
0045  * xdg_types
0046  * package_types
0047  *
0048  * Example:
0049  * /content/data?xdg_types=icons,themes,wallpapers
0050  * /content/data?package_types=1,2,3
0051  *
0052  * package_types:
0053  * 1 = AppImage
0054  * 2 = Android (apk)c
0055  * 3 = OS X compatible
0056  * 4 = Windows executable
0057  * 5 = Debian
0058  * 6 = Snappy
0059  * 7 = Flatpak
0060  * 8 = Electron-Webapp
0061  * 9 = Arch
0062  * 10 = open/Suse
0063  * 11 = Redhat
0064  * 12 = Source Code
0065  *
0066  * ----
0067  *
0068  * Additional data field of '/content/categories'
0069  *
0070  * display_name
0071  * parent_id
0072  * xdg_type
0073  *
0074  * ----
0075  *
0076  * Additional data field of '/content/data'
0077  *
0078  * xdg_type
0079  * download_package_type{n}
0080  * download_package_arch{n}
0081  *
0082  * ----
0083  *
0084  * Additional data field of '/content/download'
0085  *
0086  * download_package_type
0087  * download_package_arch
0088  *
0089  * ----
0090  *
0091  * Additional API method for preview picture
0092  *
0093  * /content/previewpic/{contentid}
0094  *
0095  * Example:
0096  * /content/previewpic/123456789
0097  * /content/previewpic/123456789?size=medium
0098  */
0099 class Ocsv1Controller extends Zend_Controller_Action
0100 {
0101 
0102     const COMMENT_TYPE_CONTENT = 1;
0103     const COMMENT_TYPE_FORUM = 4;
0104     const COMMENT_TYPE_KNOWLEDGE = 7;
0105     const COMMENT_TYPE_EVENT = 8;
0106 
0107     const DOWNLOAD_PERIOD_VALIDITY = 12; // hours
0108 
0109     const CACHE_PERIOD_VALIDITY = 1; // hour
0110 
0111     protected $_authData = null;
0112 
0113     protected $_uriScheme = 'https';
0114 
0115     protected $_format = 'xml';
0116 
0117     protected $_config = array('id'         => 'opendesktop.org',
0118                                'location'   => 'https://www.opendesktop.org/ocs/v1/',
0119                                'name'       => 'opendesktop.org',
0120                                'icon'       => '',
0121                                'termsofuse' => 'https://www.opendesktop.org/terms',
0122                                'register'   => 'https://www.opendesktop.org/register',
0123                                'version'    => '1.7',
0124                                'website'    => 'www.opendesktop.org',
0125                                'host'       => 'www.opendesktop.org',
0126                                'contact'    => 'contact@opendesktop.org',
0127                                'ssl'        => true,
0128                                'user_host'  => 'www.pling.com');
0129 
0130     protected $_params = array();
0131 
0132     protected $_allowed_format = array('json', 'xml');
0133 
0134     /**
0135      * @throws Zend_Exception
0136      */
0137     public function init()
0138     {
0139         parent::init();
0140         $this->_initUriScheme();
0141         $this->_initRequestParamsAndFormat();
0142         $this->_initConfig();
0143         $this->_initResponseHeader();
0144         $this->_initAuthorization();
0145     }
0146 
0147     /**
0148      *
0149      */
0150     protected function _initUriScheme()
0151     {
0152         $this->_uriScheme = 'http';
0153 
0154         if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === '1')) {
0155             $this->_uriScheme = 'https';
0156 
0157             return;
0158         }
0159 
0160         if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
0161             $this->_uriScheme = 'https';
0162 
0163             return;
0164         }
0165     }
0166 
0167     /**
0168      * @throws Zend_Exception
0169      */
0170     protected function _initRequestParamsAndFormat()
0171     {
0172         // Set request parameters
0173         switch (strtoupper($_SERVER['REQUEST_METHOD'])) {
0174             case 'GET':
0175                 $this->_params = $_GET + $this->getAllParams();
0176                 break;
0177             case 'PUT':
0178                 parse_str(file_get_contents('php://input'), $_PUT);
0179                 $this->_params = $_PUT;
0180                 break;
0181             case 'POST':
0182                 $this->_params = $_POST;
0183                 break;
0184             case 'OPTIONS':
0185                 header('Allow: GET,POST');
0186                 $this->_sendResponse(null, 'json');
0187                 break;
0188             default:
0189                 Zend_Registry::get('logger')
0190                              ->err(__METHOD__ . ' - request method not supported - ' . $_SERVER['REQUEST_METHOD'])
0191                 ;
0192                 exit('request method not supported');
0193         }
0194 
0195         // try to find accept header
0196         /** @var Zend_Controller_Request_Http $request */
0197         $request = $this->getRequest();
0198         $accept_header = $request->getHeader('accept');
0199         //Zend_Registry::get('logger')->debug(__METHOD__ . ' :: ' . print_r($accept_header, true));
0200         list($format) = sscanf($accept_header, "application/%s");
0201         //Zend_Registry::get('logger')->debug(__METHOD__ . ' :: ' . print_r($this->_format, true));
0202         if (in_array(strtolower($format), $this->_allowed_format)) {
0203             $this->_format = $format;
0204         }
0205 
0206         // Set format option
0207         if (isset($this->_params['format']) && strtolower($this->_params['format']) == 'json') {
0208             $this->_format = 'json';
0209         }
0210     }
0211 
0212     /**
0213      * @param        $response
0214      * @param string $format
0215      * @param string $xmlRootTag
0216      *
0217      * @throws DOMException
0218      */
0219     protected function _sendResponse($response, $format = 'xml', $xmlRootTag = 'ocs')
0220     {
0221 //        header('Pragma: public');
0222         header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT', true);
0223 
0224         header("Access-Control-Allow-Origin: *");
0225         header("Access-Control-Allow-Headers: Accept,Authorization,X-Requested-With");
0226         header("Access-Control-Request-Method: GET,POST,OPTIONS");
0227         header("Vary: Accept, Content-Type");
0228 
0229         $duration = 1800; // in seconds
0230         header('Cache-Control: max-age='.$duration);
0231 //        $expires = gmdate("D, d M Y H:i:s", time() + $duration) . " GMT";
0232 //        header('Expires: ' . $expires);
0233         if ($format == 'json') {
0234             header('Content-Type: application/json; charset=UTF-8');
0235             echo json_encode($response);
0236         } else {
0237             header('Content-Type: application/xml; charset=UTF-8');
0238             echo $this->_convertXmlDom($response, $xmlRootTag)->saveXML()
0239             ;
0240         }
0241 
0242         exit;
0243     }
0244 
0245     /**
0246      * @param                 $values
0247      * @param string          $tagName
0248      * @param DOMNode|null    $dom
0249      * @param DOMElement|null $element
0250      *
0251      * @return DomDocument|DOMNode
0252      * @throws DOMException
0253      */
0254     protected function _convertXmlDom($values, $tagName = 'data', DOMNode &$dom = null, DOMElement &$element = null)
0255     {
0256         if (!$dom) {
0257             $dom = new DomDocument('1.0', 'UTF-8');
0258         }
0259         if (!$element) {
0260             $element = $dom->appendChild($dom->createElement($tagName));
0261         }
0262         if (is_array($values) || is_object($values)) {
0263             foreach ($values as $key => $value) {
0264                 if (is_array($value) || is_object($value)) {
0265                     $isHash = false;
0266                     foreach ($value as $_key => $_value) {
0267                         if (ctype_digit((string)$_key)) {
0268                             $isHash = true;
0269                         }
0270                         break;
0271                     }
0272                     if ($isHash) {
0273                         $this->_convertXmlDom($value, $key, $dom, $element);
0274                         continue;
0275                     }
0276                     if (ctype_digit((string)$key)) {
0277                         $key = $tagName;
0278                     }
0279                     $childElement = $element->appendChild($dom->createElement($key));
0280                     $this->_convertXmlDom($value, $key, $dom, $childElement);
0281                 } else {
0282                     if ($key == '@text') {
0283                         if (is_bool($value)) {
0284                             $value = var_export($value, true);
0285                         }
0286                         $element->appendChild($dom->createTextNode($value));
0287                     } else {
0288                         if ($key == '@cdata') {
0289                             if (is_bool($value)) {
0290                                 $value = var_export($value, true);
0291                             }
0292                             $element->appendChild($dom->createCDATASection($value));
0293                         } else {
0294                             if (is_bool($value)) {
0295                                 $value = var_export($value, true);
0296                             }
0297                             $element->setAttribute($key, $value);
0298                         }
0299                     }
0300                 }
0301             }
0302         }
0303 
0304         return $dom;
0305     }
0306 
0307     /**
0308      * @return array|null
0309      * @throws Zend_Exception
0310      */
0311     protected function _loadClientConfig()
0312     {
0313         $clientConfigReader = new Application_Model_ClientConfig($this->_getNameForStoreClient());
0314         $clientConfigReader->loadClientConfig();
0315 
0316         return $clientConfigReader->getConfig();
0317     }
0318 
0319     /**
0320      * Returns the name for the store client.
0321      * If no name were found, the name for the standard store client will be returned.
0322      *
0323      * @return string
0324      * @throws Zend_Exception
0325      */
0326     protected function _getNameForStoreClient()
0327     {
0328         $clientName = Zend_Registry::get('config')->settings->client->default->name; // default client
0329         if (Zend_Registry::isRegistered('store_config_name')) {
0330             $clientName = Zend_Registry::get('store_config_name');
0331         }
0332 
0333         return $clientName;
0334     }
0335 
0336     /**
0337      *
0338      */
0339     protected function _initResponseHeader()
0340     {
0341         $duration = 1800; // in seconds
0342         $expires = gmdate("D, d M Y H:i:s", time() + $duration) . " GMT";
0343 
0344         $this->getResponse()
0345              ->setHeader('X-FRAME-OPTIONS', 'SAMEORIGIN', true)
0346              ->setHeader('Expires', $expires, true)
0347              ->setHeader('Pragma', 'cache', true)
0348              ->setHeader('Cache-Control', 'max-age=1800, public', true)
0349         ;
0350     }
0351 
0352     /**
0353      * @throws Zend_Auth_Adapter_Exception
0354      * @throws Zend_Exception
0355      */
0356     protected function _initAuthorization()
0357     {
0358         $authToken = $this->getAuthToken();
0359         if ($authToken) {
0360             $this->getAuthDataFromToken($authToken);
0361 
0362             return;
0363         }
0364         $this->_authenticateUser();
0365     }
0366 
0367     protected function getAuthToken()
0368     {
0369         $authHeader = $this->getAuthorizationHeader();
0370         list($authToken) = sscanf($authHeader, "Bearer %s");
0371 
0372 //        return sscanf( $authHeader, "Authorization: Bearer %s");
0373 
0374         return $authToken;
0375     }
0376 
0377     /**
0378      * Get header Authorization
0379      * */
0380     protected function getAuthorizationHeader()
0381     {
0382         if (isset($_SERVER['Authorization'])) {
0383             return trim($_SERVER["Authorization"]);
0384         }
0385         if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI but depends on Webserver Config
0386             return trim($_SERVER["HTTP_AUTHORIZATION"]);
0387         }
0388         if (function_exists('apache_request_headers')) {
0389             $requestHeaders = apache_request_headers();
0390             // Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
0391             $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
0392             //print_r($requestHeaders);
0393             if (isset($requestHeaders['Authorization'])) {
0394                 return trim($requestHeaders['Authorization']);
0395             }
0396         }
0397 
0398         return '';
0399     }
0400 
0401     /**
0402      * @param $authToken
0403      *
0404      * @return void
0405      */
0406     protected function getAuthDataFromToken($authToken)
0407     {
0408         try {
0409             $data = Application_Model_Jwt::decode($authToken);
0410             if ($data->exp < microtime()) {
0411                 return;
0412             }
0413 
0414             $external_id = $data->sub;
0415             if (empty($external_id)) {
0416                 return;
0417             }
0418 
0419             $modelMember = new Application_Model_Member();
0420             $member_data = $modelMember->fetchMemberDataByExternalId($external_id);
0421             $this->_authData = (object)$member_data->toArray();
0422             $auth = Zend_Auth::getInstance();
0423             $auth->clearIdentity();
0424             $auth->getStorage()->write((object)$member_data->toArray())
0425             ;
0426         } catch (Exception $e) {
0427             error_log(__METHOD__ . ' :: ' . $e->getMessage());
0428         }
0429     }
0430 
0431     /**
0432      * @param null $identity
0433      * @param null $credential
0434      * @param bool $force
0435      *
0436      * @return bool
0437      * @throws Zend_Auth_Adapter_Exception
0438      * @throws Zend_Exception
0439      *
0440      */
0441     protected function _authenticateUser($identity = null, $credential = null, $force = false)
0442     {
0443         if (!$identity && !empty($_SERVER['PHP_AUTH_USER'])) {
0444             // Will set user identity or API-Key
0445             $identity = $_SERVER['PHP_AUTH_USER'];
0446         }
0447         if (!$credential && !empty($_SERVER['PHP_AUTH_PW'])) {
0448             $credential = $_SERVER['PHP_AUTH_PW'];
0449         }
0450 
0451         if (isset($identity) && isset($credential)) {
0452             $authModel = new Application_Model_Authorization();
0453             $authData = $authModel->getAuthDataFromApi($identity, $credential);
0454             if ($authData) {
0455                 $this->_authData = $authData;
0456                 Zend_Auth::getInstance()->clearIdentity()
0457                 ;
0458                 Zend_Auth::getInstance()->getStorage()->write($authData)
0459                 ;
0460 
0461                 return true;
0462             }
0463         }
0464 
0465         if ($force) {
0466             //header('WWW-Authenticate: Basic realm="Your valid user account or api key"');
0467             header('WWW-Authenticate: Basic realm="Your valid user account"');
0468             header('HTTP/1.0 401 Unauthorized');
0469             exit;
0470         }
0471 
0472         return false;
0473     }
0474 
0475     /**
0476      * @throws Zend_Exception
0477      */
0478     public function indexAction()
0479     {
0480         $this->_sendErrorResponse(999, 'unknown request');
0481     }
0482 
0483     /**
0484      * @param        $statuscode
0485      * @param string $message
0486      *
0487      * @throws DOMException
0488      * @throws Zend_Exception
0489      */
0490     protected function _sendErrorResponse($statuscode, $message = '')
0491     {
0492         if ($this->_format == 'json') {
0493             $response = array('status'     => 'failed',
0494                               'statuscode' => $statuscode,
0495                               'message'    => $message);
0496         } else {
0497             $response = array('meta' => array('status'     => array('@text' => 'failed'),
0498                                               'statuscode' => array('@text' => $statuscode),
0499                                               'message'    => array('@text' => $message)));
0500         }
0501 
0502         Zend_Registry::get('logger')->err(json_encode($response))
0503         ;
0504         $this->_sendResponse($response, $this->_format);
0505     }
0506 
0507     public function providersAction()
0508     {
0509         // As providers.xml
0510         $response = array('provider' => array('id'         => array('@text' => $this->_config['id']),
0511                                               'location'   => array('@text' => $this->_config['location']),
0512                                               'name'       => array('@text' => $this->_config['name']),
0513                                               'icon'       => array('@text' => $this->_config['icon']),
0514                                               'termsofuse' => array('@text' => $this->_config['termsofuse']),
0515                                               'register'   => array('@text' => $this->_config['register']),
0516                                               'services'   => array('person'  => array('ocsversion' => $this->_config['version']),
0517                                                                     'content' => array('ocsversion' => $this->_config['version']))));
0518 
0519         $this->_sendResponse($response, 'xml', 'providers');
0520     }
0521 
0522     /**
0523      * @throws Zend_Exception
0524      */
0525     protected function _initConfig()
0526     {
0527         $clientConfig = $this->_loadClientConfig();
0528 
0529         $credentials = '';
0530         if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
0531             $credentials = $_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'] . '@';
0532         }
0533 
0534         $baseUri = $this->_uriScheme . '://' . $credentials . $_SERVER['SERVER_NAME'];
0535 
0536         $webSite = Zend_Registry::get('config')->settings->client->default->website;
0537 
0538         //Mask api.kde-look.org to store.kde.org
0539         if (Zend_Registry::get('config')->settings->client->special->mapping_active == true) {
0540             $mapping = Zend_Registry::get('config')->settings->client->special->mapping->toArray();
0541 
0542             $webSite = $mapping[$this->_getNameForStoreClient()] ? $mapping[$this->_getNameForStoreClient()] : $webSite;
0543         }
0544 
0545         $this->_config = array('id'         => $_SERVER['SERVER_NAME'],
0546                                'location'   => $baseUri . '/ocs/v1/',
0547                                'name'       => $clientConfig['head']['browser_title'],
0548                                'icon'       => $baseUri . $clientConfig['logo'],
0549                                'termsofuse' => $webSite . '/content/terms',
0550                                'register'   => $webSite . '/register',
0551                                'website'    => $webSite,
0552                                'host'       => $_SERVER['SERVER_NAME']) + $this->_config;
0553     }
0554 
0555     public function configAction()
0556     {
0557         if ($this->_format == 'json') {
0558             $response = array('status'     => 'ok',
0559                               'statuscode' => 100,
0560                               'message'    => '',
0561                               'data'       => array('version' => $this->_config['version'],
0562                                                     'website' => $this->_config['website'],
0563                                                     'host'    => $this->_config['host'],
0564                                                     'contact' => $this->_config['contact'],
0565                                                     'ssl'     => $this->_config['ssl']));
0566         } else {
0567             $response = array('meta' => array('status'     => array('@text' => 'ok'),
0568                                               'statuscode' => array('@text' => 100),
0569                                               'message'    => array('@text' => '')),
0570                               'data' => array('version' => array('@text' => $this->_config['version']),
0571                                               'website' => array('@text' => $this->_config['website']),
0572                                               'host'    => array('@text' => $this->_config['host']),
0573                                               'contact' => array('@text' => $this->_config['contact']),
0574                                               'ssl'     => array('@text' => $this->_config['ssl'])));
0575         }
0576 
0577         $this->_sendResponse($response, $this->_format);
0578     }
0579 
0580     public function personcheckAction()
0581     {
0582         /** @var Zend_Controller_Request_Http $request */
0583         $request = $this->getRequest();
0584         if (false === $request->isPost()) {
0585             $this->_sendErrorResponse(405, "method not allowed");
0586         }
0587         $identity = $this->getParam('login');
0588         $credential = $this->getParam('password');
0589 
0590         if (!$identity) {
0591             $this->_sendErrorResponse(101, 'please specify all mandatory fields');
0592         }
0593 
0594         $modelAuth = new Application_Model_Authorization();
0595         $authResult = $modelAuth->authenticateCredentials($identity, $credential);
0596 
0597         if (!$authResult->isValid()) {
0598             $this->_sendErrorResponse(102, 'login not valid');
0599         }
0600 
0601         if ($this->_format == 'json') {
0602             $response = array('status'     => 'ok',
0603                               'statuscode' => 100,
0604                               'message'    => '',
0605                               'data'       => array(array('details'  => 'check',
0606                                                           'personid' => $authResult->getIdentity())));
0607         } else {
0608             $response = array('meta' => array('status'     => array('@text' => 'ok'),
0609                                               'statuscode' => array('@text' => 100),
0610                                               'message'    => array('@text' => '')),
0611                               'data' => array('person' => array('details'  => 'check',
0612                                                                 'personid' => array('@text' => $authResult->getIdentity()))));
0613         }
0614 
0615         $this->_sendResponse($response, $this->_format);
0616     }
0617 
0618     /**
0619      * Gets a parameter from the {@link $_request Request object}.  If the
0620      * parameter does not exist, NULL will be returned.
0621      *
0622      * If the parameter does not exist and $default is set, then
0623      * $default will be returned instead of NULL.
0624      *
0625      * @param string $paramName
0626      * @param mixed  $default
0627      *
0628      * @return mixed
0629      */
0630     public function getParam($paramName, $default = null)
0631     {
0632         $value = isset($this->_params[$paramName]) ? $this->_params[$paramName] : null;
0633         if ((null === $value || '' === $value) && (null !== $default)) {
0634             $value = $default;
0635         }
0636 
0637         return $value;
0638     }
0639 
0640     public function personselfAction()
0641     {
0642         $this->persondataAction(true);
0643     }
0644 
0645     /**
0646      * @param bool $self
0647      *
0648      * @throws DOMException
0649      * @throws Zend_Db_Select_Exception
0650      * @throws Zend_Exception
0651      */
0652     public function persondataAction($self = false)
0653     {
0654         //See Ticket: https://phabricator.kde.org/T11173: we should show some data instead of an error
0655         $showAll = false;
0656         if (Zend_Auth::getInstance()->hasIdentity()) {
0657             $showAll = true;
0658         }
0659 
0660         $tableMember = new Application_Model_Member();
0661 
0662         // Self data or specific person data
0663         if ($self || $this->getParam('personid')) {
0664             if ($self) {
0665                 $username = $this->_authData->username;
0666             } else {
0667                 if ($this->getParam('personid')) {
0668                     $username = $this->getParam('personid');
0669                 }
0670             }
0671 
0672             $member = $tableMember->findActiveMemberByIdentity($username);
0673 
0674             if (empty($member->member_id)) {
0675                 $this->_sendErrorResponse(101, 'person not found');
0676             }
0677 
0678             $profilePage = $this->_uriScheme . '://' . $this->_config['user_host'] . '/u/' . $member->username;
0679             $avatarUrl = $this->_uriScheme . '://' . $this->_config['user_host'] . '/member/avatar/' . md5($member->mail) . '/800';
0680 
0681             $userData = array('details'              => $showAll ? 'full' : 'summary',
0682                               'personid'             => $member->username,
0683                               'privacy'              => 0,
0684                               'privacytext'          => 'public',
0685                               'firstname'            => $member->firstname,
0686                               'lastname'             => $showAll ? $member->lastname : '',
0687                               'gender'               => '',
0688                               'communityrole'        => '',
0689                               'homepage'             => $member->link_website,
0690                               'company'              => '',
0691                               'avatarpic'            => $avatarUrl,
0692                               'avatarpicfound'       => 1,
0693                               'bigavatarpic'         => $avatarUrl,
0694                               'bigavatarpicfound'    => 1,
0695                               'birthday'             => '',
0696                               'jobstatus'            => '',
0697                               'city'                 => $showAll ? $member->city : '',
0698                               'country'              => $showAll ? $member->country : '',
0699                               'latitude'             => '',
0700                               'longitude'            => '',
0701                               'ircnick'              => '',
0702                               'ircchannels'          => '',
0703                               'irclink'              => '',
0704                               'likes'                => '',
0705                               'dontlikes'            => '',
0706                               'interests'            => '',
0707                               'languages'            => '',
0708                               'programminglanguages' => '',
0709                               'favouritequote'       => '',
0710                               'favouritemusic'       => '',
0711                               'favouritetvshows'     => '',
0712                               'favouritemovies'      => '',
0713                               'favouritebooks'       => '',
0714                               'favouritegames'       => '',
0715                               'description'          => $showAll ? $member->biography : '',
0716                               'profilepage'          => $profilePage);
0717 
0718             if ($this->_format == 'json') {
0719                 $response = array('status'     => 'ok',
0720                                   'statuscode' => 100,
0721                                   'message'    => '',
0722                                   'data'       => array($userData));
0723             } else {
0724                 $userData = array('details'              => $showAll ? 'full' : 'summary',
0725                                   'personid'             => array('@text' => $member->username),
0726                                   'privacy'              => array('@text' => 0),
0727                                   'privacytext'          => array('@text' => 'public'),
0728                                   'firstname'            => array('@text' => $member->firstname),
0729                                   'lastname'             => array('@text' => $showAll ? $member->lastname : ''),
0730                                   'gender'               => array('@text' => ''),
0731                                   'communityrole'        => array('@text' => ''),
0732                                   'homepage'             => array('@text' => $member->link_website),
0733                                   'company'              => array('@text' => ''),
0734                                   'avatarpic'            => array('@text' => $avatarUrl),
0735                                   'avatarpicfound'       => array('@text' => 1),
0736                                   'bigavatarpic'         => array('@text' => $avatarUrl),
0737                                   'bigavatarpicfound'    => array('@text' => 1),
0738                                   'birthday'             => array('@text' => ''),
0739                                   'jobstatus'            => array('@text' => ''),
0740                                   'city'                 => array('@text' => $showAll ? $member->city : ''),
0741                                   'country'              => array('@text' => $showAll ? $member->country : ''),
0742                                   'latitude'             => array('@text' => ''),
0743                                   'longitude'            => array('@text' => ''),
0744                                   'ircnick'              => array('@text' => ''),
0745                                   'ircchannels'          => array('@text' => ''),
0746                                   'irclink'              => array('@text' => ''),
0747                                   'likes'                => array('@text' => ''),
0748                                   'dontlikes'            => array('@text' => ''),
0749                                   'interests'            => array('@text' => ''),
0750                                   'languages'            => array('@text' => ''),
0751                                   'programminglanguages' => array('@text' => ''),
0752                                   'favouritequote'       => array('@text' => ''),
0753                                   'favouritemusic'       => array('@text' => ''),
0754                                   'favouritetvshows'     => array('@text' => ''),
0755                                   'favouritemovies'      => array('@text' => ''),
0756                                   'favouritebooks'       => array('@text' => ''),
0757                                   'favouritegames'       => array('@text' => ''),
0758                                   'description'          => array('@text' => $showAll ? $member->biography : ''),
0759                                   'profilepage'          => array('@text' => $profilePage));
0760 
0761 
0762                 $response = array('meta' => array('status'     => array('@text' => 'ok'),
0763                                                   'statuscode' => array('@text' => 100),
0764                                                   'message'    => array('@text' => '')),
0765                                   'data' => array('person' => $userData));
0766             }
0767 
0768             $this->_sendResponse($response, $this->_format);
0769         } // Find a specific list of persons
0770         else {
0771             //Only auth users can search here
0772             if (!$showAll) {
0773                 $this->_sendErrorResponse(101, 'data is private');
0774             }
0775 
0776             $limit = 10; // 1 - 100
0777             $offset = 0;
0778 
0779             $tableMemberSelect = $tableMember->select()->where('is_active = ?', 1)->where('is_deleted = ?', 0);
0780 
0781             if (!empty($this->_params['name'])) {
0782                 $isSearchable = false;
0783                 foreach (explode(' ', $this->_params['name']) as $keyword) {
0784                     if ($keyword && strlen($keyword) > 2) {
0785                         $tableMemberSelect->where('username LIKE ?' . ' OR firstname LIKE ?' . ' OR lastname LIKE ?', "%$keyword%");
0786                         $isSearchable = true;
0787                     }
0788                 }
0789                 if (!$isSearchable) {
0790                     $tableMemberSelect->where('username LIKE ?' . ' OR firstname LIKE ?' . ' OR lastname LIKE ?', "%{$this->_params['name']}%");
0791                 }
0792             }
0793             if (!empty($this->_params['country'])) {
0794                 $tableMemberSelect->where('country = ?', $this->_params['country']);
0795             }
0796             if (!empty($this->_params['city'])) {
0797                 $tableMemberSelect->where('city = ?', $this->_params['city']);
0798             }
0799             if (!empty($this->_params['description'])) {
0800                 $isSearchable = false;
0801                 foreach (explode(' ', $this->_params['name']) as $keyword) {
0802                     if ($keyword && strlen($keyword) > 2) {
0803                         $tableMemberSelect->where('biography LIKE ?', "%$keyword%");
0804                         $isSearchable = true;
0805                     }
0806                 }
0807                 if (!$isSearchable) {
0808                     $tableMemberSelect->where('biography LIKE ?', "%$this->_params['description']}%");
0809                 }
0810             }
0811             if (!empty($this->_params['pc'])) {
0812             }
0813             if (!empty($this->_params['software'])) {
0814             }
0815             if (!empty($this->_params['longitude'])) {
0816             }
0817             if (!empty($this->_params['latitude'])) {
0818             }
0819             if (!empty($this->_params['distance'])) {
0820             }
0821             if (!empty($this->_params['attributeapp'])) {
0822             }
0823             if (!empty($this->_params['attributekey'])) {
0824             }
0825             if (!empty($this->_params['attributevalue'])) {
0826             }
0827             if (isset($this->_params['pagesize']) && ctype_digit((string)$this->_params['pagesize']) && $this->_params['pagesize'] > 0 && $this->_params['pagesize'] < 101) {
0828                 $limit = $this->_params['pagesize'];
0829             }
0830             if (isset($this->_params['page']) && ctype_digit((string)$this->_params['page'])) {
0831                 // page parameter: the first page is 0
0832                 $offset = $limit * $this->_params['page'];
0833             }
0834 
0835             $members = $tableMember->fetchAll($tableMemberSelect->limit($limit, $offset));
0836 
0837             $tableMemberSelect->reset('columns');
0838             $tableMemberSelect->reset('limitcount');
0839             $tableMemberSelect->reset('limitoffset');
0840 
0841             $count = $tableMember->fetchRow($tableMemberSelect->columns(array('count' => 'COUNT(*)')));
0842 
0843             if ($count['count'] > 1000) {
0844                 $this->_sendErrorResponse(102, 'more than 1000 people found.' . ' it is not allowed to fetch such a big resultset.' . ' please specify more search conditions');
0845             }
0846 
0847             if ($this->_format == 'json') {
0848                 $response = array('status'       => 'ok',
0849                                   'statuscode'   => 100,
0850                                   'message'      => '',
0851                                   'totalitems'   => $count['count'],
0852                                   'itemsperpage' => $limit,
0853                                   'data'         => array());
0854             } else {
0855                 $response = array('meta' => array('status'       => array('@text' => 'ok'),
0856                                                   'statuscode'   => array('@text' => 100),
0857                                                   'message'      => array('@text' => ''),
0858                                                   'totalitems'   => array('@text' => $count['count']),
0859                                                   'itemsperpage' => array('@text' => $limit)),
0860                                   'data' => array());
0861             }
0862 
0863             if (!count($members)) {
0864                 $this->_sendResponse($response, $this->_format);
0865             }
0866 
0867             $personsList = array();
0868             foreach ($members as $member) {
0869                 if ($this->_format == 'json') {
0870                     $personsList[] = array('details'       => 'summary',
0871                                            'personid'      => $member->username,
0872                                            'privacy'       => 0,
0873                                            'privacytext'   => 'public',
0874                                            'firstname'     => $member->firstname,
0875                                            'lastname'      => $member->lastname,
0876                                            'gender'        => '',
0877                                            'communityrole' => '',
0878                                            'company'       => '',
0879                                            'city'          => $member->city,
0880                                            'country'       => $member->country);
0881                 } else {
0882                     $personsList[] = array('details'       => 'summary',
0883                                            'personid'      => array('@text' => $member->username),
0884                                            'privacy'       => array('@text' => 0),
0885                                            'privacytext'   => array('@text' => 'public'),
0886                                            'firstname'     => array('@text' => $member->firstname),
0887                                            'lastname'      => array('@text' => $member->lastname),
0888                                            'gender'        => array('@text' => ''),
0889                                            'communityrole' => array('@text' => ''),
0890                                            'company'       => array('@text' => ''),
0891                                            'city'          => array('@text' => $member->city),
0892                                            'country'       => array('@text' => $member->country));
0893                 }
0894             }
0895 
0896             if ($this->_format == 'json') {
0897                 $response['data'] = $personsList;
0898             } else {
0899                 $response['data'] = array('person' => $personsList);
0900             }
0901 
0902             $this->_sendResponse($response, $this->_format);
0903         }
0904     }
0905 
0906     /**
0907      * @throws DOMException
0908      * @throws Zend_Cache_Exception
0909      * @throws Zend_Exception
0910      */
0911     public function contentcategoriesAction()
0912     {
0913         /** @var Zend_Cache_Core $cache */
0914         $cache = Zend_Registry::get('cache');
0915         $cacheName = 'content_categories_' . md5($this->_getNameForStoreClient() . $this->_format);
0916 
0917         $debugMode = (int)$this->getParam('debug') ? (int)$this->getParam('debug') : false;
0918 
0919         if (false == ($categoriesList = $cache->load($cacheName))) {
0920             $categoriesList = $this->_buildCategories();
0921             $cache->save($categoriesList, $cacheName, array(), 900);
0922         }
0923 
0924         if ($this->_format == 'json') {
0925             $response = array('status'     => 'ok',
0926                               'statuscode' => 100,
0927                               'message'    => '',
0928                               'totalitems' => count($categoriesList),
0929                               'data'       => array());
0930             if (!empty($categoriesList)) {
0931                 $response['data'] = $categoriesList;
0932             }
0933         } else {
0934             $response = array('meta' => array('status'     => array('@text' => 'ok'),
0935                                               'statuscode' => array('@text' => 100),
0936                                               'message'    => array('@text' => ''),
0937                                               'totalitems' => array('@text' => count($categoriesList))),
0938                               'data' => array());
0939             if (!empty($categoriesList)) {
0940                 $response['data'] = array('category' => $categoriesList);
0941             }
0942         }
0943 
0944         if ($debugMode) {
0945             $response['meta']['debug']['store_client_name'] = $this->_getNameForStoreClient();
0946             $response['meta']['debug']['param_store_client_name'] = $this->getParam('domain_store_id');
0947         }
0948 
0949         $etag = md5(json_encode($response));
0950         header("Etag: $etag");
0951         $this->_sendResponse($response, $this->_format);
0952     }
0953 
0954     /**
0955      * @return array
0956      */
0957     protected function _buildCategories()
0958     {
0959         $modelCategoryTree = new Application_Model_ProjectCategory();
0960         $tree = $modelCategoryTree->fetchCategoryTreeCurrentStore();
0961 
0962         return $this->buildResponseTree($tree);
0963     }
0964 
0965     /**
0966      * @param array $tree
0967      *
0968      * @return array
0969      */
0970     protected function buildResponseTree($tree)
0971     {
0972         $result = array();
0973         foreach ($tree as $element) {
0974             if ($this->_format == 'json') {
0975                 $result[] = array('id'           => $element['id'],
0976                                   'name'         => (false === empty($element['name_legacy'])) ? $element['name_legacy'] : $element['title'],
0977                                   'display_name' => $element['title'],
0978                                   'parent_id'    => (false === empty($element['parent_id'])) ? $element['parent_id'] : '',
0979                                   'xdg_type'     => (false === empty($element['xdg_type'])) ? $element['xdg_type'] : '');
0980             } else {
0981                 $result[] = array('id'           => array('@text' => $element['id']),
0982                                   'name'         => array('@text' => (false === empty($element['name_legacy'])) ? $element['name_legacy'] : $element['title']),
0983                                   'display_name' => array('@text' => $element['title']),
0984                                   'parent_id'    => array('@text' => (false === empty($element['parent_id'])) ? $element['parent_id'] : ''),
0985                                   'xdg_type'     => array('@text' => (false === empty($element['xdg_type'])) ? $element['xdg_type'] : ''));
0986             }
0987             if ($element['has_children']) {
0988                 $sub_tree = $this->buildResponseTree($element['children']);
0989                 $result = array_merge($result, $sub_tree);
0990             }
0991         }
0992 
0993         return $result;
0994     }
0995 
0996     /**
0997      * @throws Zend_Auth_Storage_Exception
0998      * @throws Zend_Exception
0999      * @throws Zend_Cache_Exception
1000      * @throws Zend_Auth_Adapter_Exception
1001      * @throws Zend_Db_Select_Exception
1002      * @throws Zend_Db_Statement_Exception
1003      * @throws DOMException
1004      */
1005     public function contentdataAction()
1006     {
1007         /* @deprecated use Zend_Auth::getInstance() instead */
1008         //$this->_authenticateUser();
1009 
1010         $pploadApi = new Ppload_Api(array('apiUri'   => PPLOAD_API_URI,
1011                                           'clientId' => PPLOAD_CLIENT_ID,
1012                                           'secret'   => PPLOAD_SECRET));
1013         $previewPicSize = array('width'  => 770,
1014                                 'height' => 540,
1015                                 'crop'   => 0);
1016         $smallPreviewPicSize = array('width'  => 100,
1017                                      'height' => 100,
1018                                      'crop'   => 0);
1019 
1020         $debugMode = (int)$this->getParam('debug') ? (int)$this->getParam('debug') : false;
1021         $nocache = (int)$this->getParam('nocache') ? (int)$this->getParam('nocache') : false;
1022 
1023         // Specific content data
1024         $requestedId = (int)$this->getParam('content_id') ? (int)$this->getParam('content_id') : null;
1025         if (!$requestedId) {
1026             $requestedId = (int)$this->getParam('contentid') ? (int)$this->getParam('contentid') : null;
1027         }
1028 
1029 
1030         if ($requestedId) {
1031             $response = $this->fetchContent($requestedId, $previewPicSize, $smallPreviewPicSize, $pploadApi);
1032 
1033             $this->_sendResponse($response, $this->_format);
1034         } // Gets a list of a specific set of contents
1035         else {
1036             $response = $this->fetchCategoryContent($previewPicSize, $smallPreviewPicSize, $pploadApi, $debugMode, $nocache);
1037 
1038             $this->_sendResponse($response, $this->_format);
1039         }
1040     }
1041 
1042     /**
1043      * @param int        $contentId
1044      * @param array      $previewPicSize
1045      * @param array      $smallPreviewPicSize
1046      * @param Ppload_Api $pploadApi
1047      *
1048      * @return array
1049      * @throws DOMException
1050      * @throws Zend_Cache_Exception
1051      * @throws Zend_Db_Select_Exception
1052      * @throws Zend_Exception
1053      */
1054     protected function fetchContent($contentId,
1055                                     $previewPicSize,
1056                                     $smallPreviewPicSize,
1057                                     $pploadApi)
1058     {
1059         /** @var Zend_Cache_Core $cache */
1060         $cache = Zend_Registry::get('cache');
1061         $cacheName = 'api_fetch_content_by_id_' . $contentId . $this->_format . md5($this->_getNameForStoreClient());
1062 
1063         if (($response = $cache->load($cacheName))) {
1064             return $response;
1065         }
1066 
1067         $tableProject = new Application_Model_Project();
1068         $tableProjectSelect = $this->_buildProjectSelect($tableProject);
1069 
1070         $project = $tableProject->fetchRow($tableProjectSelect->where('project.project_id = ?', $contentId));
1071 
1072         if (!$project) {
1073             $this->_sendErrorResponse(101, 'content not found');
1074         }
1075 
1076         $project->title = Application_Model_HtmlPurify::purify($project->title);
1077         $project->description = Application_Model_BBCode::renderHtml(Application_Model_HtmlPurify::purify($project->description));
1078         $project->version = Application_Model_HtmlPurify::purify($project->version);
1079 
1080         $categoryXdgType = '';
1081         if (!empty($project->cat_xdg_type)) {
1082             $categoryXdgType = $project->cat_xdg_type;
1083         }
1084 
1085         $created = date('c', strtotime($project->created_at));
1086         $changed = date('c', strtotime($project->changed_at));
1087 
1088         $previewPage = $this->_uriScheme . '://' . $this->_config['website'] . '/p/' . $project->project_id;
1089 
1090         $donationPage = $previewPage;
1091         if (empty($project->paypal_mail) && empty($project->dwolla_id)) {
1092             $donationPage = '';
1093         }
1094 
1095         list($previewPics, $smallPreviewPics) = $this->getGalleryPictures($project, $previewPicSize, $smallPreviewPicSize);
1096 
1097         $downloads = $project->count_downloads_hive;
1098         list($downloadItems, $downloads) = $this->getPPLoadInfo($project, $pploadApi, $downloads);
1099 
1100         $score = $project->laplace_score;
1101         $score = round($score / 10, 0);
1102 
1103         $projTags = "";
1104         //special for plasma-version-tags
1105         if (!empty($project->tags)) {
1106             //get File-Tags from Product
1107             $fileTagArray = explode(',', $project->tags);
1108             //collect tags
1109             $tagTable = new Application_Model_Tags();
1110             $plasmaversionTags = $tagTable->getAllFilePlasmaVersionTags();
1111             foreach ($fileTagArray as $tag) {
1112                 if (in_array($tag, $plasmaversionTags)) {
1113                     $version = null;
1114                     $pos = strrpos($tag, '-');
1115                     if ($pos) {
1116                         $version = substr($tag, $pos + 1);
1117                     }
1118                     $projTags .= "plasma##majorversion=" . $version . ",";
1119                 } else {
1120                     $projTags .= $tag . ",";
1121                 }
1122             }
1123 
1124             $projTags = rtrim($projTags, ",");
1125         }
1126 
1127         if ($this->_format == 'json') {
1128             $response = array('status'     => 'ok',
1129                               'statuscode' => 100,
1130                               'message'    => '',
1131                               'data'       => array(array('details'              => 'full',
1132                                                           'id'                   => $project->project_id,
1133                                                           'name'                 => $project->title,
1134                                                           'version'              => $project->version,
1135                                                           'typeid'               => $project->project_category_id,
1136                                                           'typename'             => $project->cat_title,
1137                                                           'xdg_type'             => $categoryXdgType,
1138                                                           'language'             => '',
1139                                                           'personid'             => $project->username,
1140                                                           'created'              => $created,
1141                                                           'changed'              => $changed,
1142                                                           'downloads'            => $downloads,
1143                                                           'score'                => $score,
1144                                                           'summary'              => '',
1145                                                           'description'          => $project->description,
1146                                                           'changelog'            => '',
1147                                                           'feedbackurl'          => $previewPage,
1148                                                           'homepage'             => $previewPage,
1149                                                           'homepagetype'         => '',
1150                                                           'donationpage'         => $donationPage,
1151                                                           'comments'             => $project->count_comments,
1152                                                           'commentspage'         => $previewPage,
1153                                                           'fans'                 => null,
1154                                                           'fanspage'             => '',
1155                                                           'knowledgebaseentries' => null,
1156                                                           'knowledgebasepage'    => '',
1157                                                           'depend'               => '',
1158                                                           'preview1'             => $previewPage,
1159                                                           'icon'                 => '',
1160                                                           'video'                => '',
1161                                                           'detailpage'           => $previewPage,
1162                                                           'ghns_excluded'        => $project->ghns_excluded,
1163                                                           'tags'                 => $projTags) + $previewPics + $smallPreviewPics + $downloadItems));
1164         } else {
1165             foreach ($previewPics as $key => $value) {
1166                 $previewPics[$key] = array('@text' => $value);
1167             }
1168             foreach ($smallPreviewPics as $key => $value) {
1169                 $smallPreviewPics[$key] = array('@text' => $value);
1170             }
1171             if ($downloadItems) {
1172                 foreach ($downloadItems as $key => $value) {
1173                     $downloadItems[$key] = array('@text' => $value);
1174                 }
1175             }
1176             $response = array('meta' => array('status'     => array('@text' => 'ok'),
1177                                               'statuscode' => array('@text' => 100),
1178                                               'message'    => array('@text' => '')),
1179                               'data' => array('content' => array('details'              => 'full',
1180                                                                  'id'                   => array('@text' => $project->project_id),
1181                                                                  'name'                 => array('@text' => $project->title),
1182                                                                  'version'              => array('@text' => $project->version),
1183                                                                  'typeid'               => array('@text' => $project->project_category_id),
1184                                                                  'typename'             => array('@text' => $project->cat_title),
1185                                                                  'xdg_type'             => array('@text' => $categoryXdgType),
1186                                                                  'language'             => array('@text' => ''),
1187                                                                  'personid'             => array('@text' => $project->username),
1188                                                                  'created'              => array('@text' => $created),
1189                                                                  'changed'              => array('@text' => $changed),
1190                                                                  'downloads'            => array('@text' => $downloads),
1191                                                                  'score'                => array('@text' => $score),
1192                                                                  'summary'              => array('@text' => ''),
1193                                                                  'description'          => array('@cdata' => $project->description),
1194                                                                  'changelog'            => array('@text' => ''),
1195                                                                  'feedbackurl'          => array('@text' => $previewPage),
1196                                                                  'homepage'             => array('@text' => $previewPage),
1197                                                                  'homepagetype'         => array('@text' => ''),
1198                                                                  'donationpage'         => array('@text' => $donationPage),
1199                                                                  'comments'             => array('@text' => $project->count_comments),
1200                                                                  'commentspage'         => array('@text' => $previewPage),
1201                                                                  'fans'                 => array('@text' => null),
1202                                                                  'fanspage'             => array('@text' => ''),
1203                                                                  'knowledgebaseentries' => array('@text' => null),
1204                                                                  'knowledgebasepage'    => array('@text' => ''),
1205                                                                  'depend'               => array('@text' => ''),
1206                                                                  'preview1'             => array('@text' => $previewPage),
1207                                                                  'icon'                 => array('@text' => ''),
1208                                                                  'video'                => array('@text' => ''),
1209                                                                  'detailpage'           => array('@text' => $previewPage),
1210                                                                  'ghns_excluded'        => array('@text' => $project->ghns_excluded),
1211                                                                  'tags'                 => array('@text' => $projTags)) + $previewPics + $smallPreviewPics + $downloadItems));
1212         }
1213 
1214         $cache->save($response, $cacheName);
1215 
1216         return $response;
1217     }
1218 
1219     /**
1220      * @param Zend_Db_Table $tableProject
1221      *
1222      * @param bool          $withSqlCalcFoundRows
1223      *
1224      * @return Zend_Db_Table_Select
1225      * @throws Zend_Db_Select_Exception
1226      */
1227     protected function _buildProjectSelect($tableProject, $withSqlCalcFoundRows = false)
1228     {
1229         $tableProjectSelect = $tableProject->select();
1230         if ($withSqlCalcFoundRows) {
1231             $tableProjectSelect->from(array('project' => 'stat_projects'), array(new Zend_Db_Expr('SQL_CALC_FOUND_ROWS *')));
1232         } else {
1233             $tableProjectSelect->from(array('project' => 'stat_projects'));
1234         }
1235         $tableProjectSelect->setIntegrityCheck(false)
1236                            ->columns(array(
1237                                            'member_username' => 'username',
1238                                            'category_title'  => 'cat_title',
1239                                            'xdg_type'        => 'cat_xdg_type',
1240                                            'name_legacy'     => 'cat_name_legacy',
1241                                            new Zend_Db_Expr("(select count(1) as num_files from ppload.ppload_files f where f.active = 1 and f.collection_id = project.ppload_collection_id group by f.collection_id) as num_files"),
1242                                            new Zend_Db_Expr("(select count(1) AS `amount` from `stat_downloads_24h` `s` WHERE s.collection_id = project.ppload_collection_id group by `s`.`collection_id`) as num_dls"),
1243                                            new Zend_Db_Expr("(select sum(downloaded_count) from ppload.ppload_files pf where pf.collection_id = project.ppload_collection_id and `active` = 1 and ocs_compatible = 1) as num_downloads")
1244                                      )
1245                            )
1246                            ->where('project.status = ?', Application_Model_DbTable_Project::PROJECT_ACTIVE)
1247                            ->where('project.ppload_collection_id IS NOT NULL')
1248         ;
1249         $tableProjectSelect->having('num_files > 0');
1250 
1251         return $tableProjectSelect;
1252     }
1253 
1254     /**
1255      * @param Zend_Db_Table_Row_Abstract $project
1256      * @param array                      $previewPicSize
1257      * @param array                      $smallPreviewPicSize
1258      *
1259      * @return array
1260      * @throws Zend_Cache_Exception
1261      * @throws Zend_Exception
1262      */
1263     protected function getGalleryPictures($project, $previewPicSize, $smallPreviewPicSize)
1264     {
1265         /** @var Zend_Cache_Core $cache */
1266         $cache = Zend_Registry::get('cache');
1267         $cacheName = 'api_fetch_gallery_pics_' . $project->project_id;
1268 
1269         if (($previews = $cache->load($cacheName))) {
1270             return $previews;
1271         }
1272 
1273         $viewHelperImage = new Application_View_Helper_Image();
1274         $previewPics = array('previewpic1' => $viewHelperImage->Image($project->image_small, $previewPicSize));
1275         $smallPreviewPics = array('smallpreviewpic1' => $viewHelperImage->Image($project->image_small, $smallPreviewPicSize));
1276 
1277         $tableProject = new Application_Model_Project();
1278         $galleryPics = $tableProject->getGalleryPictureSources($project->project_id);
1279         if ($galleryPics) {
1280             $i = 2;
1281             foreach ($galleryPics as $galleryPic) {
1282                 $previewPics['previewpic' . $i] = $viewHelperImage->Image($galleryPic, $previewPicSize);
1283                 $smallPreviewPics['smallpreviewpic' . $i] = $viewHelperImage->Image($galleryPic, $smallPreviewPicSize);
1284                 $i++;
1285             }
1286         }
1287 
1288         $cache->save(array($previewPics, $smallPreviewPics), $cacheName);
1289 
1290         return array($previewPics, $smallPreviewPics);
1291     }
1292 
1293     /**
1294      * @param Zend_Db_Table_Row_Abstract $project
1295      * @param Ppload_Api                 $pploadApi
1296      * @param int                        $downloads
1297      * @param string                     $fileIds
1298      *
1299      * @return array
1300      * @throws Zend_Cache_Exception
1301      * @throws Zend_Exception
1302      */
1303     protected function getPPLoadInfo($project, $pploadApi, $downloads, $fileIds = null)
1304     {
1305         $downloadItems = array();
1306 
1307         if (empty($project->ppload_collection_id)) {
1308             return array($downloadItems, $downloads);
1309         }
1310 
1311         /** @var Zend_Cache_Core $cache */
1312         $cache = Zend_Registry::get('cache');
1313         $cacheName = 'api_ppload_collection_by_id_' . $project->ppload_collection_id;
1314 
1315         if ($fileIds && count($fileIds) > 0) {
1316             $cacheName .= '_' . md5($fileIds);
1317         }
1318 
1319 //        if (false !== ($pploadInfo = $cache->load($cacheName))) {
1320 //            return $pploadInfo;
1321 //        }
1322 
1323         $tagTable = new Application_Model_Tags();
1324 
1325         //if filter for fileIds
1326         //if($fileIds && count($fileIds) > 0) {
1327         //    $filesRequest['ids'] = $fileIds;
1328         //}
1329 
1330         //Load Files from DB
1331         $pploadFileTable = new Application_Model_DbTable_PploadFiles();
1332         $files = $pploadFileTable->fetchAllActiveFilesForFileInfo($project->ppload_collection_id, $fileIds);
1333 
1334         $sql = "    SELECT  *
1335                      FROM `ppload`.`ppload_files` `f` 
1336                      WHERE `f`.`collection_id` = :collection_id 
1337                      AND `f`.`ocs_compatible` = 1 
1338                      AND `f`.`active` = 1
1339                    ";
1340         if (null != $fileIds && count($fileIds) > 0) {
1341             $sql .= " and f.id in (" . $fileIds . ")";
1342         }
1343 
1344         $packageTypeTags = $tagTable->getAllFilePackageTypeTags();
1345         $architectureTags = $tagTable->getAllFileArchitectureTags();
1346         $plasmaversionTags = $tagTable->getAllFilePlasmaVersionTags();
1347 
1348         $i = 1;
1349         foreach ($files as $file) {
1350             //get File-Tags from DB
1351             $fileTagArray = $tagTable->getTagsAsArray($file['id'], $tagTable::TAG_TYPE_FILE);
1352 
1353             //create ppload download hash: secret + collection_id + expire-timestamp
1354             list($timestamp, $hash) = $this->createDownloadHash($project);
1355 
1356             //$tags = $this->_parseFileTags($file->tags);
1357 
1358             //collect tags
1359             $fileTags = "";
1360 
1361             //mimetype
1362             // $fileTags .= "data##mimetype=" . $file['type'] . ",";
1363             if ($file['type'] && strpos($file['type'], 'charset=') !== false) {
1364                 $types = explode(";", $file['type']);
1365                 if (sizeof($types) == 2) {
1366                     $fileTags .= "data##mimetype=" . trim($types[0]) . ",";
1367                     $fileTags .= "data##" . trim($types[1]) . ",";
1368                 } else {
1369                     $fileTags .= "data##mimetype=" . $file['type'] . ",";
1370                 }
1371             } else {
1372                 $fileTags .= "data##mimetype=" . $file['type'] . ",";
1373             }
1374 
1375             //$fileTags .= "tags=".$fileTagArray->__toString().",";
1376 
1377 
1378             $tagTable = new Application_Model_Tags();
1379 
1380             foreach ($fileTagArray as $tag) {
1381                 if (in_array($tag, $packageTypeTags)) {
1382                     $fileTags .= "application##packagetype=" . $tag . ",";
1383                 } else {
1384                     if (in_array($tag, $architectureTags)) {
1385                         $fileTags .= "application##architecture=" . $tag . ",";
1386                     } else {
1387                         if (in_array($tag, $plasmaversionTags)) {
1388                             $version = null;
1389                             $pos = strrpos($tag, '-');
1390                             if ($pos) {
1391                                 $version = substr($tag, $pos + 1);
1392                             }
1393                             $fileTags .= "plasma##majorversion=" . $version . ",";
1394                         }
1395                     }
1396                 }
1397             }
1398 
1399             $fileTags = rtrim($fileTags, ",");
1400 
1401 
1402             $downloads += (int)$file['downloaded_count'];
1403 
1404             //$downloadLink = PPLOAD_API_URI . 'files/download/id/' . $file['id'] . '/s/' . $hash . '/t/' . $timestamp . '/o/1/' . $file['name'];
1405 
1406             $payload = array('id' => $file['id'], 'o' => '1');
1407             $downloadLink = Application_Model_PpLoad::createDownloadUrlJwt($project->ppload_collection_id, $file['name'], $payload);
1408 
1409             $downloadItems['downloadway' . $i] = 1;
1410             $downloadItems['downloadtype' . $i] = '';
1411             $downloadItems['downloadprice' . $i] = '0';
1412             $downloadItems['downloadlink' . $i] = $downloadLink;
1413             $downloadItems['downloadname' . $i] = $file['name'];
1414             $downloadItems['downloadsize' . $i] = round($file['size'] / 1024);
1415             $downloadItems['downloadgpgfingerprint' . $i] = '';
1416             $downloadItems['downloadgpgsignature' . $i] = '';
1417             $downloadItems['downloadpackagename' . $i] = '';
1418             $downloadItems['downloadrepository' . $i] = '';
1419             $downloadItems['download_package_type' . $i] = null;
1420             $downloadItems['download_package_arch' . $i] = null;
1421             //$downloadItems['downloadtags' . $i] = empty($tags['filetags']) ? '' : implode(',', $tags['filetags']);
1422             $downloadItems['downloadtags' . $i] = empty($fileTags) ? '' : $fileTags;
1423             $downloadItems['downloadmd5sum' . $i] = empty($file['md5sum']) ? '' : $file['md5sum'];
1424             $i++;
1425 
1426         }
1427 
1428         $cache->save(array($downloadItems, $downloads), $cacheName, array(), (self::CACHE_PERIOD_VALIDITY * 3600));
1429 
1430         return array($downloadItems, $downloads);
1431     }
1432 
1433     /**
1434      * @param $project
1435      *
1436      * @return array
1437      */
1438     protected function createDownloadHash($project)
1439     {
1440         //create ppload download hash: secret + collection_id + expire-timestamp
1441         $salt = PPLOAD_DOWNLOAD_SECRET;
1442         $collectionID = $project->ppload_collection_id;
1443         $timestamp = time() + (3600 * self::DOWNLOAD_PERIOD_VALIDITY);
1444         $hash = md5($salt . $collectionID . $timestamp);
1445 
1446         return array($timestamp, $hash);
1447     }
1448 
1449     /**
1450      * @param array      $previewPicSize
1451      * @param array      $smallPreviewPicSize
1452      * @param Ppload_Api $pploadApi
1453      * @param boolean    $debugMode Is debug mode
1454      *
1455      * @param bool       $nocache
1456      *
1457      * @return array
1458      * @throws Zend_Auth_Adapter_Exception
1459      * @throws Zend_Auth_Storage_Exception
1460      * @throws Zend_Cache_Exception
1461      * @throws Zend_Db_Select_Exception
1462      * @throws Zend_Db_Statement_Exception
1463      * @throws Zend_Exception
1464      */
1465     protected function fetchCategoryContent($previewPicSize,
1466                                             $smallPreviewPicSize,
1467                                             $pploadApi,
1468                                             $debugMode,
1469                                             $nocache = false)
1470     {
1471         $limit = 10; // 1 - 100
1472         $offset = 0;
1473 
1474         $tableProject = new Application_Model_Project();
1475         $tableProjectSelect = $this->_buildProjectSelect($tableProject, true);
1476 
1477         $storeTags = Zend_Registry::isRegistered('config_store_tags') ? Zend_Registry::get('config_store_tags') : null;
1478 
1479         if ($storeTags) {
1480             $tagList = $storeTags;
1481             //build where statement für projects
1482             $selectAnd = $tableProject->select();
1483             $selectAndFiles = $tableProject->select();
1484 
1485             $tableTags = new Application_Model_Tags();
1486             $possibleFileTags = $tableTags->fetchAllFileTagNamesAsArray();
1487 
1488             if (!is_array($tagList)) {
1489                 $tagList = array($tagList);
1490             }
1491 
1492             foreach ($tagList as $item) {
1493                 #and
1494                 $selectAnd->where('find_in_set(?, tag_ids)', $item);
1495                 if (in_array($item, $possibleFileTags)) {
1496                     $selectAndFiles->where('find_in_set(?, tag_ids)', $item);
1497                 } else {
1498                     $selectAndFiles->where("1=1");
1499                 }
1500             }
1501             $tableProjectSelect->where(implode(' ', $selectAnd->getPart('where')));
1502         }
1503 
1504         if (false === empty($this->_params['categories'])) {
1505             // categories parameter: values separated by ","
1506             // legacy OCS API compatible: values separated by "x"
1507             if (strpos($this->_params['categories'], ',') !== false) {
1508                 $catList = explode(',', $this->_params['categories']);
1509             } else {
1510                 $catList = explode('x', $this->_params['categories']);
1511             }
1512 
1513             $modelProjectCategories = new Application_Model_DbTable_ProjectCategory();
1514             $allCategories = array_merge($catList, $modelProjectCategories->fetchChildIds($catList));
1515             $tableProjectSelect->where('project.project_category_id IN (?)', $allCategories);
1516         }
1517 
1518         if (!empty($this->_params['xdg_types'])) {
1519             // xdg_types parameter: values separated by ","
1520             $xdgTypeList = explode(',', $this->_params['xdg_types']);
1521             $tableProjectSelect->where('category.xdg_type IN (?)', $xdgTypeList);
1522         }
1523 
1524         $hasSearchPart = false;
1525         if (false === empty($this->_params['search'])) {
1526             foreach (explode(' ', $this->_params['search']) as $keyword) {
1527                 if ($keyword && strlen($keyword) > 2) {
1528                     $tableProjectSelect->where('project.title LIKE ? OR project.description LIKE ?', "%$keyword%");
1529                     $hasSearchPart = true;
1530                 }
1531             }
1532         }
1533 
1534         if (false === empty($this->_params['tags'])) {
1535             // tags parameter: values separated by "," and | for or filter
1536             if (strpos($this->_params['tags'], ',') !== false) {
1537                 $tagList = explode(',', $this->_params['tags']);
1538             } else {
1539                 $tagList = array($this->_params['tags']);
1540             }
1541 
1542             //build where statement for projects
1543             $selectAnd = $tableProject->select();
1544             $selectAndFiles = $tableProject->select();
1545 
1546             $tableTags = new Application_Model_Tags();
1547             $possibleFileTags = $tableTags->fetchAllFileTagNamesAsArray();
1548 
1549             foreach ($tagList as $item) {
1550                 if (strpos($item, '|') !== false) {
1551                     #or
1552                     $selectOr = $tableProject->select();
1553                     $selectOrFiles = $tableProject->select();
1554                     $tagListOr = explode('|', $item);
1555                     foreach ($tagListOr as $itemOr) {
1556                         $selectOr->orWhere('find_in_set(?, tags)', $itemOr);
1557                         if (in_array($itemOr, $possibleFileTags)) {
1558                             $selectOrFiles->orWhere('find_in_set(?, tags)', $itemOr);
1559                         }
1560                     }
1561                     $selectAnd->where(implode(' ', $selectOr->getPart('where')));
1562 
1563                     $selectAndFiles->where(implode(' ', $selectOrFiles->getPart('where')));
1564                 } else {
1565                     #and
1566                     $selectAnd->where('find_in_set(?, tags)', $item);
1567                     if (in_array($item, $possibleFileTags)) {
1568                         $selectAndFiles->where('find_in_set(?, tags)', $item);
1569                     } else {
1570                         $selectAndFiles->where("1=1");
1571                     }
1572                 }
1573 
1574             }
1575             $tableProjectSelect->where(implode(' ', $selectAnd->getPart('where')));
1576         } else {
1577             $selectAndFiles = $tableProject->select();
1578             $selectAndFiles->where("1=1");
1579         }
1580 
1581         if (!empty($this->_params['ghns_excluded'])) {
1582             $tableProjectSelect->where('project.ghns_excluded = ?', $this->_params['ghns_excluded']);
1583         }
1584 
1585         if (!empty($this->_params['user'])) {
1586             $tableProjectSelect->where('project.username = ?', $this->_params['user']);
1587         }
1588 
1589         if (!empty($this->_params['external'])) {
1590         }
1591 
1592         if (!empty($this->_params['distribution'])) {
1593             // distribution parameter: comma separated list of ids
1594         }
1595 
1596         if (!empty($this->_params['showfavorites'])) {
1597             // if = 1 then show auth users favorites
1598             if ($this->_params['showfavorites'] == 1 && null != $this->_authData) {
1599                 $member_id = $this->_authData->member_id;
1600                 $tableProjectSelect->where('project_follower.member_id = ?', $member_id);
1601                 $tableProjectSelect->setIntegrityCheck(false)
1602                                    ->join('project_follower', 'project.project_id = project_follower.project_id', array('project_follower_id'))
1603                 ;
1604             }
1605         }
1606 
1607         if (!empty($this->_params['license'])) {
1608             // license parameter: comma separated list of ids
1609         }
1610 
1611         if (!empty($this->_params['sortmode'])) {
1612             // sortmode parameter: new|alpha|high|down
1613             switch (strtolower($this->_params['sortmode'])) {
1614                 case 'new':
1615                     $tableProjectSelect->order('project.created_at DESC');
1616 
1617                     break;
1618                 case 'alpha':
1619                     $tableProjectSelect->order('project.title ASC');
1620 
1621                     break;
1622                 case 'high':
1623                     $tableProjectSelect->order('laplace_score DESC');
1624                     $tableProjectSelect->order('project.created_at DESC');
1625 
1626                     break;
1627                 case 'down':
1628                     $tableProjectSelect->order('num_downloads DESC');
1629                     $tableProjectSelect->order('project.created_at DESC');
1630 
1631                     break;
1632                 default:
1633                     break;
1634             }
1635         }
1636 
1637         if (isset($this->_params['pagesize']) && ctype_digit((string)$this->_params['pagesize']) && $this->_params['pagesize'] > 0 && $this->_params['pagesize'] < 101) {
1638             $limit = $this->_params['pagesize'];
1639         }
1640 
1641         if (isset($this->_params['page']) && ctype_digit((string)$this->_params['page'])) {
1642             // page parameter: the first page is 0
1643             $offset = $limit * $this->_params['page'];
1644         }
1645 
1646         $tableProjectSelect->limit($limit, $offset);
1647 
1648 
1649         /** @var Zend_Cache_Core $cache */
1650         $cache = Zend_Registry::get('cache');
1651         $storeName = Zend_Registry::get('store_config')->name;
1652         $cacheName = 'api_fetch_category_' . md5($tableProjectSelect->__toString() . '_' . $selectAndFiles->__toString() . '_' . $storeName . '_' . $this->_format);
1653         $cacheNameCount = 'api_fetch_category_' . md5($tableProjectSelect->__toString() . '_' . $selectAndFiles->__toString() . '_' . $storeName . '_' . $this->_format) . '_count';
1654         $contentsList = false;
1655         $count = 0;
1656         $isFromCache = false;
1657 
1658         //ignore cache, if param nocache is set
1659         if ($nocache == true) {
1660             $projects = $tableProject->fetchAll($tableProjectSelect);
1661             $counter = $tableProject->getAdapter()->fetchRow('select FOUND_ROWS() AS counter');
1662             $count = $counter['counter'];
1663 
1664             if (count($projects) > 0) {
1665                 $contentsList = $this->_buildContentList($previewPicSize, $smallPreviewPicSize, $pploadApi, $projects, implode(' ', $selectAndFiles->getPart('where')));
1666             } else {
1667                 $contentsList = array();
1668             }
1669         } else {
1670             if (false === $hasSearchPart) {
1671                 $contentsList = $cache->load($cacheName);
1672                 $count = $cache->load($cacheNameCount);
1673             }
1674 
1675             if (false == $contentsList) {
1676                 $projects = $tableProject->fetchAll($tableProjectSelect);
1677                 $counter = $tableProject->getAdapter()->fetchRow('select FOUND_ROWS() AS counter');
1678                 $count = $counter['counter'];
1679 
1680                 if (count($projects) > 0) {
1681                     $contentsList = $this->_buildContentList($previewPicSize, $smallPreviewPicSize, $pploadApi, $projects, implode(' ', $selectAndFiles->getPart('where')));
1682                     if (false === $hasSearchPart) {
1683                         $cache->save($contentsList, $cacheName, array(), 900);
1684                         $cache->save($count, $cacheNameCount, array(), 900);
1685                     }
1686                 } else {
1687                     $contentsList = array();
1688                 }
1689             } else {
1690                 $isFromCache = true;
1691             }
1692         }
1693 
1694         if ($this->_format == 'json') {
1695             $response = array('status'       => 'ok',
1696                               'statuscode'   => 100,
1697                               'message'      => '',
1698                               'totalitems'   => $count,
1699                               'itemsperpage' => $limit,
1700                               'data'         => $contentsList);
1701         } else {
1702             $response = array('meta' => array('status'       => array('@text' => 'ok'),
1703                                               'statuscode'   => array('@text' => 100),
1704                                               'message'      => array('@text' => ''),
1705                                               'totalitems'   => array('@text' => $count),
1706                                               'itemsperpage' => array('@text' => $limit)),
1707                               'data' => array());
1708             if (count($contentsList) > 0) {
1709                 $response['data']['content'] = $contentsList;
1710             }
1711         }
1712 
1713 
1714         if ($debugMode) {
1715             $response['meta']['debug']['is_from_cache_now'] = $isFromCache;
1716             $response['meta']['debug']['select_project'] = $tableProjectSelect->__toString();
1717             $response['meta']['debug']['select_files'] = $selectAndFiles->__toString();
1718             $response['meta']['debug']['store_client_name'] = $this->_getNameForStoreClient();
1719             $response['meta']['debug']['param_store_client_name'] = $this->getParam('domain_store_id');
1720             $response['meta']['debug']['hello'] = 'World';
1721         }
1722 
1723         return $response;
1724     }
1725 
1726     /**
1727      * @param        $previewPicSize
1728      * @param        $smallPreviewPicSize
1729      * @param        $pploadApi
1730      * @param        $projects
1731      * @param String $selectWhereString
1732      *
1733      * @return array
1734      * @throws Zend_Cache_Exception
1735      * @throws Zend_Exception
1736      */
1737     protected function _buildContentList($previewPicSize,
1738                                          $smallPreviewPicSize,
1739                                          $pploadApi,
1740                                          $projects,
1741                                          $selectWhereString)
1742     {
1743         $contentsList = array();
1744         $helperTruncate = new Application_View_Helper_Truncate();
1745         $selectWhereString = ' AND ' . $selectWhereString;
1746         foreach ($projects as $project) {
1747             $project->description = $helperTruncate->truncate(Application_Model_BBCode::renderHtml(Application_Model_HtmlPurify::purify($project->description)), 300);
1748 
1749             $categoryXdgType = '';
1750             if (!empty($project->xdg_type)) {
1751                 $categoryXdgType = $project->xdg_type;
1752             }
1753 
1754             $created = date('c', strtotime($project->created_at));
1755             $changed = date('c', strtotime($project->changed_at));
1756 
1757             $previewPage = $this->_uriScheme . '://' . $this->_config['website'] . '/p/' . $project->project_id;
1758 
1759             list($previewPics, $smallPreviewPics) = $this->getGalleryPictures($project, $previewPicSize, $smallPreviewPicSize);
1760 
1761             $downloads = $project->count_downloads_hive;
1762 
1763             //Get Files from OCS-API
1764             //get the list of file-ids from tags-filter
1765             $fileIds = "";
1766             $filesList = array();
1767             $tableTags = new Application_Model_Tags();
1768             $filesList = $tableTags->getFilesForTags($project->project_id, $selectWhereString);
1769 
1770             //if there is a tag filter and we have found any files, skip this project
1771             if ($selectWhereString <> ' AND (1=1)' && (empty($filesList) || count($filesList) == 0)) {
1772                 //echo "No files found for project ".$project->project_id;
1773                 continue;
1774             }
1775 
1776             foreach ($filesList as $file) {
1777                 $fileIds .= $file['file_id'] . ',';
1778             }
1779             $fileIds = rtrim($fileIds, ",");
1780 
1781             //var_dump($fileIds);
1782 
1783             list($downloadItems, $downloads) = $this->getPPLoadInfo($project, $pploadApi, $downloads, $fileIds);
1784 
1785             //If no files available, do not show this project
1786             if (empty($downloadItems)) {
1787                 continue; // jump to next product
1788             }
1789 
1790             $score = $project->laplace_score;
1791             $score = round($score / 10, 0);
1792 
1793             $projTags = "";
1794             //special for plasma-version-tags
1795             if (!empty($project->tags)) {
1796                 //get File-Tags from Product
1797                 $fileTagArray = explode(',', $project->tags);
1798                 //collect tags
1799                 $tagTable = new Application_Model_Tags();
1800                 $plasmaversionTags = $tagTable->getAllFilePlasmaVersionTags();
1801                 foreach ($fileTagArray as $tag) {
1802                     if (in_array($tag, $plasmaversionTags)) {
1803                         $version = null;
1804                         $pos = strrpos($tag, '-');
1805                         if ($pos) {
1806                             $version = substr($tag, $pos + 1);
1807                         }
1808                         $projTags .= "plasma##majorversion=" . $version . ",";
1809                     } else {
1810                         $projTags .= $tag . ",";
1811                     }
1812                 }
1813 
1814                 $projTags = rtrim($projTags, ",");
1815             }
1816 
1817             if ($this->_format == 'json') {
1818                 $contentsList[] = array('details'       => 'summary',
1819                                         'id'            => $project->project_id,
1820                                         'name'          => $project->title,
1821                                         'version'       => $project->version,
1822                                         'typeid'        => $project->project_category_id,
1823                                         'typename'      => $project->cat_title,
1824                                         'xdg_type'      => $categoryXdgType,
1825                                         'language'      => '',
1826                                         'personid'      => $project->member_username,
1827                                         'created'       => $created,
1828                                         'changed'       => $changed,
1829                                         'downloads'     => $project->num_downloads,
1830                                         'score'         => $score,
1831                                         'summary'       => '',
1832                                         'description'   => $project->description,
1833                                         'comments'      => $project->count_comments,
1834                                         'ghns_excluded' => $project->ghns_excluded,
1835                                         'preview1'      => $previewPage,
1836                                         'detailpage'    => $previewPage,
1837                                         'tags'          => $projTags) + $previewPics + $smallPreviewPics + $downloadItems;
1838             } else {
1839                 foreach ($previewPics as $key => $value) {
1840                     $previewPics[$key] = array('@text' => $value);
1841                 }
1842                 foreach ($smallPreviewPics as $key => $value) {
1843                     $smallPreviewPics[$key] = array('@text' => $value);
1844                 }
1845                 if ($downloadItems) {
1846                     foreach ($downloadItems as $key => $value) {
1847                         $downloadItems[$key] = array('@text' => $value);
1848                     }
1849                 }
1850                 $contentsList[] = array('details'       => 'summary',
1851                                         'id'            => array('@text' => $project->project_id),
1852                                         'name'          => array('@text' => $project->title),
1853                                         'version'       => array('@text' => $project->version),
1854                                         'typeid'        => array('@text' => $project->project_category_id),
1855                                         'typename'      => array('@text' => $project->cat_title),
1856                                         'xdg_type'      => array('@text' => $categoryXdgType),
1857                                         'language'      => array('@text' => ''),
1858                                         'personid'      => array('@text' => $project->member_username),
1859                                         'created'       => array('@text' => $created),
1860                                         'changed'       => array('@text' => $changed),
1861                                         'downloads'     => array('@text' => $project->num_downloads),
1862                                         'score'         => array('@text' => $score),
1863                                         'summary'       => array('@text' => ''),
1864                                         'description'   => array('@cdata' => $project->description),
1865                                         'comments'      => array('@text' => $project->count_comments),
1866                                         'ghns_excluded' => array('@text' => $project->ghns_excluded),
1867                                         'preview1'      => array('@text' => $previewPage),
1868                                         'detailpage'    => array('@text' => $previewPage),
1869                                         'tags'          => array('@text' => $projTags)) + $previewPics + $smallPreviewPics + $downloadItems;
1870             }
1871         }
1872 
1873         return $contentsList;
1874     }
1875 
1876     /**
1877      * @throws DOMException
1878      * @throws Zend_Exception
1879      */
1880     public function contentdownloadAction()
1881     {
1882         $project = null;
1883         $file = null;
1884 
1885         if ($this->getParam('contentid')) {
1886             $tableProject = new Application_Model_Project();
1887             $project = $tableProject->fetchRow($tableProject->select()
1888                                                             ->where('project_id = ?', $this->getParam('contentid'))
1889                                                             ->where('status = ?', Application_Model_DbTable_Project::PROJECT_ACTIVE));
1890         }
1891 
1892         if (!$project) {
1893             $this->_sendErrorResponse(101, 'content not found');
1894         }
1895 
1896         if (((int)$this->getParam('itemid')) === 0) {
1897             $this->_sendErrorResponse(103, 'content item not found');
1898         }
1899 
1900         if ($project->ppload_collection_id && $this->getParam('itemid') && ctype_digit((string)$this->getParam('itemid'))) {
1901             $tagTable = new Application_Model_Tags();
1902 
1903             //Load Files from DB
1904             $pploadFileTable = new Application_Model_DbTable_PploadFiles();
1905             $files = $pploadFileTable->fetchActiveFileWithIndex($project->ppload_collection_id, $this->getParam('itemid'));
1906 
1907             if (empty($files)) {
1908                 $this->_sendErrorResponse(103, 'content item not found');
1909             }
1910 
1911             $packageTypeTags = $tagTable->getAllFilePackageTypeTags();
1912             $architectureTags = $tagTable->getAllFileArchitectureTags();
1913             $plasmaversionTags = $tagTable->getAllFilePlasmaVersionTags();
1914 
1915             $fileTags = "";
1916             foreach ($files as $file) {
1917                 //get File-Tags from DB
1918                 $fileTagArray = $tagTable->getTagsAsArray($file['id'], $tagTable::TAG_TYPE_FILE);
1919 
1920                 //create ppload download hash: secret + collection_id + expire-timestamp
1921                 list($timestamp, $hash) = $this->createDownloadHash($project);
1922 
1923                 //$tags = $this->_parseFileTags($file->tags);
1924 
1925                 //collect tags
1926                 $fileTags = "";
1927 
1928                 //mimetype
1929                 //$fileTags .= "data##mimetype=" . $file['type'] . ",";
1930 
1931                 if ($file['type'] && strpos($file['type'], 'charset=') !== false) {
1932                     $types = explode(";", $file['type']);
1933                     if (sizeof($types) == 2) {
1934                         $fileTags .= "data##mimetype=" . trim($types[0]) . ",";
1935                         $fileTags .= "data##" . trim($types[1]) . ",";
1936                     } else {
1937                         $fileTags .= "data##mimetype=" . $file['type'] . ",";
1938                     }
1939                 } else {
1940                     $fileTags .= "data##mimetype=" . $file['type'] . ",";
1941                 }
1942 
1943                 //$fileTags .= "tags=".$fileTagArray->__toString().",";
1944 
1945 
1946                 $tagTable = new Application_Model_Tags();
1947 
1948                 foreach ($fileTagArray as $tag) {
1949                     if (in_array($tag, $packageTypeTags)) {
1950                         $fileTags .= "application##packagetype=" . $tag . ",";
1951                     } else {
1952                         if (in_array($tag, $architectureTags)) {
1953                             $fileTags .= "application##architecture=" . $tag . ",";
1954                         } else {
1955                             if (in_array($tag, $plasmaversionTags)) {
1956                                 $version = null;
1957                                 $pos = strrpos($tag, '-');
1958                                 if ($pos) {
1959                                     $version = substr($tag, $pos + 1);
1960                                 }
1961                                 $fileTags .= "plasma##majorversion=" . $version . ",";
1962                             }
1963                         }
1964                     }
1965                 }
1966 
1967                 $fileTags = rtrim($fileTags, ",");
1968 
1969                 //$downloadLink = PPLOAD_API_URI . 'files/download/id/' . $file['id'] . '/s/' . $hash . '/t/' . $timestamp . '/o/1/' . $file['name'];
1970 
1971                 $payload = array('id' => $file['id'], 'o' => '1');
1972                 $downloadLink = Application_Model_PpLoad::createDownloadUrlJwt($project->ppload_collection_id, $file['name'], $payload);
1973 
1974                 if ($this->_format == 'json') {
1975                     $response = array('status'     => 'ok',
1976                                       'statuscode' => 100,
1977                                       'message'    => '',
1978                                       'data'       => array(array('details'               => 'download',
1979                                                                   'downloadway'           => 1,
1980                                                                   'downloadlink'          => $downloadLink,
1981                                                                   'mimetype'              => $file['type'],
1982                                                                   'gpgfingerprint'        => '',
1983                                                                   'gpgsignature'          => '',
1984                                                                   'packagename'           => '',
1985                                                                   'repository'            => '',
1986                                                                   'download_package_type' => null,
1987                                                                   'download_package_arch' => null,
1988                                                                   'downloadtags'          => empty($fileTags) ? '' : $fileTags,
1989                                                                   'downloadmd5sum'        => empty($file['md5sum']) ? '' : $file['md5sumd'])));
1990                 } else {
1991                     $response = array('meta' => array('status'     => array('@text' => 'ok'),
1992                                                       'statuscode' => array('@text' => 100),
1993                                                       'message'    => array('@text' => '')),
1994                                       'data' => array('content' => array('details'               => 'download',
1995                                                                          'downloadway'           => array('@text' => 1),
1996                                                                          'downloadlink'          => array('@text' => $downloadLink),
1997                                                                          'mimetype'              => array('@text' => $file['type']),
1998                                                                          'gpgfingerprint'        => array('@text' => ''),
1999                                                                          'gpgsignature'          => array('@text' => ''),
2000                                                                          'packagename'           => array('@text' => ''),
2001                                                                          'repository'            => array('@text' => ''),
2002                                                                          'download_package_type' => array('@text' => ''),
2003                                                                          'download_package_arch' => array('@text' => ''),
2004                                                                          'downloadtags'          => array('@text' => empty($fileTags) ? '' : $fileTags),
2005                                                                          'downloadmd5sum'        => array('@text' => empty($file['md5sum']) ? '' : $file['md5sum']))));
2006                 }
2007 
2008             }
2009 
2010         }
2011 
2012         $this->_sendResponse($response, $this->_format);
2013     }
2014 
2015     public function contentpreviewpicAction()
2016     {
2017         $project = null;
2018 
2019         if ($this->getParam('contentid')) {
2020             $tableProject = new Application_Model_Project();
2021             $project = $tableProject->fetchRow($tableProject->select()
2022                                                             ->where('project_id = ?', $this->getParam('contentid'))
2023                                                             ->where('status = ?', Application_Model_DbTable_Project::PROJECT_ACTIVE));
2024         }
2025 
2026         if (!$project) {
2027             //$this->_sendErrorResponse(101, 'content not found');
2028             header('Location: ' . $this->_config['icon']);
2029             exit;
2030         }
2031 
2032         $previewPicSize = array('width'  => 100,
2033                                 'height' => 100);
2034 
2035         if (!empty($this->_params['size']) && strtolower($this->_params['size']) == 'medium') {
2036             $previewPicSize = array('width'  => 770,
2037                                     'height' => 540);
2038         }
2039 
2040         $viewHelperImage = new Application_View_Helper_Image();
2041         $previewPicUri = $viewHelperImage->Image($project->image_small, $previewPicSize);
2042 
2043         header('Location: ' . $previewPicUri);
2044         exit;
2045     }
2046 
2047     /**
2048      * @throws Zend_Exception
2049      * @throws Zend_Cache_Exception
2050      * @throws DOMException
2051      */
2052     public function commentsAction()
2053     {
2054         if ($this->_format == 'json') {
2055             $response = array('status'     => 'ok',
2056                               'statuscode' => 100,
2057                               'message'    => '',
2058                               'data'       => array());
2059         } else {
2060             $response = array('meta' => array('status'     => array('@text' => 'ok'),
2061                                               'statuscode' => array('@text' => 100),
2062                                               'message'    => array('@text' => ''),),
2063                               'data' => array());
2064         }
2065 
2066         $commentType = (int)$this->getParam('comment_type', -1);
2067         if ($commentType != self::COMMENT_TYPE_CONTENT) {
2068             $this->_sendResponse($response, $this->_format);
2069         }
2070 
2071         $contentId = (int)$this->getParam('content_id', null);
2072         if (empty($contentId)) {
2073             $this->_sendResponse($response, $this->_format);
2074         }
2075 
2076         $page = (int)$this->getParam('page', 0) + 1;
2077         $pagesize = (int)$this->getParam('pagesize', 10);
2078 
2079         /** @var Zend_Cache_Core $cache */
2080         $cache = Zend_Registry::get('cache');
2081         $cacheName = 'api_fetch_comments_' . md5("{$commentType}, {$contentId}");
2082 
2083         if (false === ($comments = $cache->load($cacheName))) {
2084             $modelComments = new Application_Model_ProjectComments();
2085             $comments = $modelComments->getCommentsHierarchic($contentId);
2086             $cache->save($comments, $cacheName, array(), 900);
2087         }
2088 
2089         if ($comments->count() == 0) {
2090             $this->_sendResponse($response, $this->_format);
2091         }
2092 
2093         $comments->setCurrentPageNumber($page);
2094         $comments->setItemCountPerPage($pagesize);
2095 
2096         if ($page > $comments->getPages()->pageCount) {
2097             $this->_sendResponse($response, $this->_format);
2098         }
2099 
2100         $response['data'] = $this->_buildCommentList($comments->getCurrentItems());
2101 
2102         $this->_sendResponse($response, $this->_format);
2103     }
2104 
2105     /**
2106      * @param Traversable $currentItems
2107      *
2108      * @return array
2109      */
2110     protected function _buildCommentList($currentItems)
2111     {
2112         $commentList = array();
2113         foreach ($currentItems as $current_item) {
2114             if ($this->_format == 'json') {
2115                 $comment = array('id'         => $current_item['comment_id'],
2116                                  'subject'    => $current_item['comment_subject'],
2117                                  'text'       => Application_Model_HtmlPurify::purify($current_item['comment_text_trim']),
2118                                  'childcount' => $current_item['childcount'],
2119                                  'user'       => $current_item['username'],
2120                                  'date'       => date('c', strtotime($current_item['comment_created_at'])),
2121                                  'score'      => $current_item['comment_score']);
2122                 if ($current_item['childcount'] > 0) {
2123                     $comment['children'] = $this->_buildCommentList($current_item['children']);
2124                 }
2125             } else {
2126                 $comment = array('id'         => array('@text' => $current_item['comment_id']),
2127                                  'subject'    => array('@text' => $current_item['comment_subject']),
2128                                  'text'       => array('@text' => Application_Model_HtmlPurify::purify($current_item['comment_text_trim'])),
2129                                  'childcount' => array('@text' => $current_item['childcount']),
2130                                  'user'       => array('@text' => $current_item['username']),
2131                                  'date'       => array('@text' => date('c', strtotime($current_item['comment_created_at']))),
2132                                  'score'      => array('@text' => $current_item['comment_score']));
2133                 if ($current_item['childcount'] > 0) {
2134                     $comment['children'] = $this->_buildCommentList($current_item['children']);
2135                 }
2136             }
2137             $commentList[] = array('comment' => $comment);
2138         }
2139 
2140         return $commentList;
2141     }
2142 
2143     /**
2144      * @return void
2145      * @throws DOMException
2146      * @throws Zend_Auth_Adapter_Exception
2147      * @throws Zend_Exception
2148      * @throws DOMException
2149      */
2150     public function voteAction()
2151     {
2152         //20191215 enable rating
2153         //$this->_sendErrorResponse(405, "method not allowed");
2154 
2155 
2156         if ($this->_authenticateUser(null, null, true)) {
2157 
2158             Zend_Registry::get('logger')->info('Start Voting')
2159             ;
2160 
2161             if ($this->hasParam('contentid') && $this->hasParam('vote')) {
2162                 $score = (int)$this->getParam('vote');
2163 
2164                 if ($score >= 0 && $score <= 100) {
2165                     $msg = '';
2166 
2167                     if ($this->hasParam('msg')) {
2168                         $msg = trim($this->getParam('msg'));
2169                     }
2170 
2171                     $project_id = (int)$this->getParam('contentid');
2172                     $status = 'ok';
2173                     $message = '';
2174 
2175                     Zend_Registry::get('logger')->info('ProjectId: ' . $project_id . ', Vote: ' . $score)
2176                     ;
2177 
2178                     if ($score > 0) {
2179                         $score = $this->roundFunction($score) / 10;
2180                     }
2181 
2182                     if ($score == 0) {
2183                         $score = 1;
2184                     }
2185 
2186                     if ($msg != '' && strlen($msg) > 0) {
2187                         $message = $msg;
2188                     } else {
2189                         //Get message via score
2190                         switch ($score) {
2191                             case 1:
2192                                 $message = '1 ugh';
2193                                 break;
2194                             case 2:
2195                                 $message = '2 really bad';
2196                                 break;
2197                             case 3:
2198                                 $message = '3 bad';
2199                                 break;
2200                             case 4:
2201                                 $message = '4 soso';
2202                                 break;
2203                             case 5:
2204                                 $message = '5 average';
2205                                 break;
2206                             case 6:
2207                                 $message = '6 okay';
2208                                 break;
2209                             case 7:
2210                                 $message = '7 good';
2211                                 break;
2212                             case 8:
2213                                 $message = '8 great';
2214                                 break;
2215                             case 9:
2216                                 $message = '9 excellent';
2217                                 break;
2218                             case 10:
2219                                 $message = '10 the best';
2220                                 break;
2221 
2222                             default:
2223                                 break;
2224                         }
2225                     }
2226 
2227                     Zend_Registry::get('logger')->info('Comment: ' . $message)
2228                     ;
2229 
2230                     //$product = $this->loadProductInfo((int)$this->getParam('p'));
2231                     $member_id = $this->_authData->member_id;
2232 
2233                     Zend_Registry::get('logger')->info('MemberId: ' . $member_id)
2234                     ;
2235 
2236                     /*
2237                     if($this->view->product->member_id==$this->view->member_id)
2238                     {
2239                         $this->_helper->json(array('status' => 'error', 'message' => ' Not allowed. ', 'data' => ''));
2240                         return;
2241                     }
2242                      *
2243                      */
2244 
2245                     try {
2246                         $modelRating = new Application_Model_DbTable_ProjectRating(array('db' => 'db2'));
2247                         $modelRating->scoreForProject($project_id, $member_id, $score, $message);
2248                     } catch (Exception $exc) {
2249                         Zend_Registry::get('logger')
2250                                      ->err('Error Saving Vote: ' . $exc->getMessage() . PHP_EOL . $exc->getTraceAsString())
2251                         ;
2252                         $this->_sendErrorResponse(500, $exc->getMessage() . PHP_EOL . $exc->getTraceAsString());
2253                     }
2254 
2255 
2256                     /*
2257                     if($this->view->product){
2258                         //Send a notification to the owner
2259                         $this->sendNotificationToOwner($this->view->product, Default_Model_HtmlPurify::purify($this->getParam('msg')));
2260                     }
2261                      *
2262                      */
2263 
2264                     if ($this->_format == 'json') {
2265                         $response = array('status'     => $status,
2266                                           'statuscode' => 100,
2267                                           'message'    => $message,
2268                                           'data'       => '',
2269                                           'score'      => $score);
2270                     } else {
2271                         $response = array('meta' => array('status'     => array('@text' => $status),
2272                                                           'statuscode' => array('@text' => 100),
2273                                                           'message'    => array('@text' => $message),
2274                                                           'score'      => array('@text' => $score)),
2275                                           'data' => array('@text' => ''));
2276                     }
2277 
2278                     Zend_Registry::get('logger')->info('Done: ' . json_encode($response))
2279                     ;
2280 
2281                     //$this->_helper->json(array('status' => $status, 'message' => $message, 'data' => '','laplace_score' =>$this->view->product->laplace_score));
2282 
2283                     $this->_sendResponse($response, $this->_format);
2284                 } else {
2285 
2286                     $this->_sendErrorResponse(101, 'please specify all mandatory fields');
2287 
2288                 }
2289 
2290             } else {
2291 
2292                 $this->_sendErrorResponse(101, 'please specify all mandatory fields');
2293 
2294             }
2295         } else {
2296             $this->_sendErrorResponse(102, 'login not valid');
2297         }
2298 
2299     }
2300 
2301     /**
2302      * @param $n
2303      *
2304      * @return float|int
2305      */
2306     function roundFunction($n)
2307     {
2308         // Smaller multiple
2309         $a = (int)($n / 10) * 10;
2310 
2311         // Larger multiple
2312         $b = ($a + 10);
2313 
2314         // Return of closest of two
2315         return ($n - $a > $b - $n) ? $b : $a;
2316     }
2317 
2318     /**
2319      * @param string $fileTags
2320      *
2321      * @return array
2322      */
2323     protected function _parseFileTags($fileTags)
2324     {
2325         $tags = explode(',', $fileTags);
2326         $parsedTags = array('link'           => '',
2327                             'licensetype'    => '',
2328                             'packagetypeid'  => '',
2329                             'architectureid' => '',
2330                             'packagearch'    => '',
2331                             'filetags'       => '');
2332         foreach ($tags as $tag) {
2333             $tag = trim($tag);
2334             if (strpos($tag, 'link##') === 0) {
2335                 $parsedTags['link'] = urldecode(str_replace('link##', '', $tag));
2336             } else {
2337                 if (strpos($tag, 'licensetype-') === 0) {
2338                     $parsedTags['licensetype'] = str_replace('licensetype-', '', $tag);
2339                 } else {
2340                     if (strpos($tag, 'packagetypeid-') === 0) {
2341                         $parsedTags['packagetypeid'] = str_replace('packagetypeid-', '', $tag);
2342                     } else {
2343                         if (strpos($tag, 'architectureid-') === 0) {
2344                             $parsedTags['architectureid'] = str_replace('architectureid-', '', $tag);
2345                         } else {
2346                             if (strpos($tag, 'packagearch-') === 0) {
2347                                 $parsedTags['packagearch'] = str_replace('packagearch-', '', $tag);
2348                             } else {
2349                                 if (strpos($tag, '@@@') === 0) {
2350                                     $strTags = substr($tag, 3, strlen($tag) - 2);
2351                                     $parsedTags['filetags'] = explode('@@', $strTags);
2352                                 }
2353                             }
2354                         }
2355                     }
2356                 }
2357             }
2358         }
2359 
2360         return $parsedTags;
2361     }
2362 
2363 }