Esempio n. 1
0
 /**
  * Display user login form.
  * Redirect to user index page if user is already validated.
  */
 function index($args, $request)
 {
     $this->setupTemplate($request);
     if (Validation::isLoggedIn()) {
         $this->sendHome($request);
     }
     if (Config::getVar('security', 'force_login_ssl') && $request->getProtocol() != 'https') {
         // Force SSL connections for login
         $request->redirectSSL();
     }
     $sessionManager = SessionManager::getManager();
     $session = $sessionManager->getUserSession();
     $templateMgr = TemplateManager::getManager($request);
     // If the user wasn't expecting a login page, i.e. if they're new to the
     // site and want to submit a paper, it helps to explain why they need to
     // register.
     if ($request->getUserVar('loginMessage')) {
         $templateMgr->assign('loginMessage', $request->getUserVar('loginMessage'));
     }
     $templateMgr->assign('username', $session->getSessionVar('username'));
     $templateMgr->assign('remember', $request->getUserVar('remember'));
     $templateMgr->assign('source', $request->getUserVar('source'));
     $templateMgr->assign('showRemember', Config::getVar('general', 'session_lifetime') > 0);
     // For force_login_ssl with base_url[...]: make sure SSL used for login form
     $loginUrl = $this->_getLoginUrl($request);
     if (Config::getVar('security', 'force_login_ssl')) {
         $loginUrl = PKPString::regexp_replace('/^http:/', 'https:', $loginUrl);
     }
     $templateMgr->assign('loginUrl', $loginUrl);
     $templateMgr->display('frontend/pages/userLogin.tpl');
 }
 /**
  * Generate a filename for a library file.
  * @param $type int LIBRARY_FILE_TYPE_...
  * @param $originalFileName string
  * @return string
  */
 function generateFileName($type, $originalFileName)
 {
     $libraryFileDao = DAORegistry::getDAO('LibraryFileDAO');
     $suffix = $this->getFileSuffixFromType($type);
     $ext = $this->getExtension($originalFileName);
     $truncated = $this->truncateFileName($originalFileName, 127 - PKPString::strlen($suffix) - 1);
     $baseName = PKPString::substr($truncated, 0, PKPString::strpos($originalFileName, $ext) - 1);
     // Try a simple syntax first
     $fileName = $baseName . '-' . $suffix . '.' . $ext;
     if (!$libraryFileDao->filenameExists($this->contextId, $fileName)) {
         return $fileName;
     }
     for ($i = 1;; $i++) {
         $fullSuffix = $suffix . '-' . $i;
         //truncate more if necessary
         $truncated = $this->truncateFileName($originalFileName, 127 - PKPString::strlen($fullSuffix) - 1);
         // get the base name and append the suffix
         $baseName = PKPString::substr($truncated, 0, PKPString::strpos($originalFileName, $ext) - 1);
         //try the following
         $fileName = $baseName . '-' . $fullSuffix . '.' . $ext;
         if (!$libraryFileDao->filenameExists($this->contextId, $fileName)) {
             return $fileName;
         }
     }
 }
 /**
  * Format XML for single DC element.
  * @param $propertyName string
  * @param $value array
  * @param $multilingual boolean optional
  */
 function formatElement($propertyName, $values, $multilingual = false)
 {
     if (!is_array($values)) {
         $values = array($values);
     }
     // Translate the property name to XML syntax.
     $openingElement = str_replace(array('[@', ']'), array(' ', ''), $propertyName);
     $closingElement = PKPString::regexp_replace('/\\[@.*/', '', $propertyName);
     // Create the actual XML entry.
     $response = '';
     foreach ($values as $key => $value) {
         if ($multilingual) {
             $key = str_replace('_', '-', $key);
             assert(is_array($value));
             foreach ($value as $subValue) {
                 if ($key == METADATA_DESCRIPTION_UNKNOWN_LOCALE) {
                     $response .= "\t<{$openingElement}>" . OAIUtils::prepOutput($subValue) . "</{$closingElement}>\n";
                 } else {
                     $response .= "\t<{$openingElement} xml:lang=\"{$key}\">" . OAIUtils::prepOutput($subValue) . "</{$closingElement}>\n";
                 }
             }
         } else {
             assert(is_scalar($value));
             $response .= "\t<{$openingElement}>" . OAIUtils::prepOutput($value) . "</{$closingElement}>\n";
         }
     }
     return $response;
 }
 /**
  * Split a string into a clean array of keywords
  * @param $text string
  * @param $allowWildcards boolean
  * @return array of keywords
  */
 static function filterKeywords($text, $allowWildcards = false)
 {
     $minLength = Config::getVar('search', 'min_word_length');
     $stopwords = self::_loadStopwords();
     // Join multiple lines into a single string
     if (is_array($text)) {
         $text = join("\n", $text);
     }
     $cleanText = Core::cleanVar($text);
     // Remove punctuation
     $cleanText = PKPString::regexp_replace('/[!"\\#\\$%\'\\(\\)\\.\\?@\\[\\]\\^`\\{\\}~]/', '', $cleanText);
     $cleanText = PKPString::regexp_replace('/[\\+,:;&\\/<=>\\|\\\\]/', ' ', $cleanText);
     $cleanText = PKPString::regexp_replace('/[\\*]/', $allowWildcards ? '%' : ' ', $cleanText);
     $cleanText = PKPString::strtolower($cleanText);
     // Split into words
     $words = PKPString::regexp_split('/\\s+/', $cleanText);
     // FIXME Do not perform further filtering for some fields, e.g., author names?
     // Remove stopwords
     $keywords = array();
     foreach ($words as $k) {
         if (!isset($stopwords[$k]) && PKPString::strlen($k) >= $minLength && !is_numeric($k)) {
             $keywords[] = PKPString::substr($k, 0, SEARCH_KEYWORD_MAX_LENGTH);
         }
     }
     return $keywords;
 }
 /**
  * @see TypeDescription::parseTypeName()
  */
 function parseTypeName($typeName)
 {
     // Standard validators are based on string input.
     parent::parseTypeName('string');
     // Split the type name into validator name and arguments.
     $typeNameParts = explode('(', $typeName, 2);
     switch (count($typeNameParts)) {
         case 1:
             // no argument
             $this->_validatorArgs = '';
             break;
         case 2:
             // parse arguments (no UTF8-treatment necessary)
             if (substr($typeNameParts[1], -1) != ')') {
                 return false;
             }
             // FIXME: Escape for PHP code inclusion?
             $this->_validatorArgs = substr($typeNameParts[1], 0, -1);
             break;
     }
     // Validator name must start with a lower case letter
     // and may contain only alphanumeric letters.
     if (!PKPString::regexp_match('/^[a-z][a-zA-Z0-9]+$/', $typeNameParts[0])) {
         return false;
     }
     // Translate the validator name into a validator class name.
     $this->_validatorClassName = 'Validator' . PKPString::ucfirst($typeNameParts[0]);
     return true;
 }
 /**
  * @copydoc Filter::process()
  * @param $citationString string
  * @return MetadataDescription
  */
 function &process(&$input)
 {
     $nullVar = null;
     $queryParams = array('demo' => '3', 'textlines' => $input);
     // Parscit web form - the result is (mal-formed) HTML
     if (is_null($result = $this->callWebService(PARSCIT_WEBSERVICE, $queryParams, XSL_TRANSFORMER_DOCTYPE_STRING, 'POST'))) {
         return $nullVar;
     }
     $result = html_entity_decode($result);
     // Detect errors.
     if (!PKPString::regexp_match('/.*<algorithm[^>]+>.*<\\/algorithm>.*/s', $result)) {
         $translationParams = array('filterName' => $this->getDisplayName());
         $this->addError(__('submission.citations.filter.webserviceResultTransformationError', $translationParams));
         return $nullVar;
     }
     // Screen-scrape the tagged portion and turn it into XML.
     $xmlResult = PKPString::regexp_replace('/.*<algorithm[^>]+>(.*)<\\/algorithm>.*/s', '\\1', $result);
     $xmlResult = PKPString::regexp_replace('/&/', '&amp;', $xmlResult);
     // Transform the result into an array of meta-data.
     if (is_null($metadata = $this->transformWebServiceResults($xmlResult, dirname(__FILE__) . DIRECTORY_SEPARATOR . 'parscit.xsl'))) {
         return $nullVar;
     }
     // Extract a publisher from the place string if possible.
     $metadata =& $this->fixPublisherNameAndLocation($metadata);
     return $this->getNlm30CitationDescriptionFromMetadataArray($metadata);
 }
Esempio n. 7
0
 /**
  * @copydoc Form::display
  */
 function display($request = null, $template = null)
 {
     import('lib.pkp.classes.xslt.XSLTransformer');
     $templateMgr = TemplateManager::getManager($request);
     $templateMgr->assign(array('localeOptions' => $this->supportedLocales, 'localesComplete' => $this->localesComplete, 'clientCharsetOptions' => $this->supportedClientCharsets, 'connectionCharsetOptions' => $this->supportedConnectionCharsets, 'databaseCharsetOptions' => $this->supportedDatabaseCharsets, 'allowFileUploads' => get_cfg_var('file_uploads') ? __('common.yes') : __('common.no'), 'maxFileUploadSize' => get_cfg_var('upload_max_filesize'), 'databaseDriverOptions' => $this->checkDBDrivers(), 'supportsMBString' => PKPString::hasMBString() ? __('common.yes') : __('common.no'), 'phpIsSupportedVersion' => version_compare(PHP_REQUIRED_VERSION, PHP_VERSION) != 1, 'xslEnabled' => XSLTransformer::checkSupport(), 'xslRequired' => REQUIRES_XSL, 'phpRequiredVersion' => PHP_REQUIRED_VERSION, 'phpVersion' => PHP_VERSION));
     parent::display();
 }
 /**
  * Assign parameters to template
  * @param $paramArray array
  */
 function assignParams($paramArray = array())
 {
     $submission = $this->submission;
     $application = PKPApplication::getApplication();
     $request = $application->getRequest();
     parent::assignParams(array_merge(array('submissionTitle' => strip_tags($submission->getLocalizedTitle()), 'submissionId' => $submission->getId(), 'submissionAbstract' => PKPString::html2text($submission->getLocalizedAbstract()), 'authorString' => strip_tags($submission->getAuthorString())), $paramArray));
 }
 /**
  * @copydoc Filter::process()
  * @param $isbn string
  * @return MetadataDescription a looked up citation description
  *  or null if the filter fails
  */
 function &process($isbn)
 {
     $nullVar = null;
     // Instantiate the web service request
     $lookupParams = array('access_key' => $this->getApiKey(), 'index1' => 'isbn', 'results' => 'details,authors', 'value1' => $isbn);
     // Call the web service
     if (is_null($resultDOM =& $this->callWebService(ISBNDB_WEBSERVICE_URL, $lookupParams))) {
         return $nullVar;
     }
     // Transform and pre-process the web service result
     if (is_null($metadata =& $this->transformWebServiceResults($resultDOM, dirname(__FILE__) . DIRECTORY_SEPARATOR . 'isbndb.xsl'))) {
         return $nullVar;
     }
     // Extract place and publisher from the combined entry.
     $metadata['publisher-loc'] = PKPString::trimPunctuation(PKPString::regexp_replace('/^(.+):.*/', '\\1', $metadata['place-publisher']));
     $metadata['publisher-name'] = PKPString::trimPunctuation(PKPString::regexp_replace('/.*:([^,]+),?.*/', '\\1', $metadata['place-publisher']));
     unset($metadata['place-publisher']);
     // Reformat the publication date
     $metadata['date'] = PKPString::regexp_replace('/^[^\\d{4}]+(\\d{4}).*/', '\\1', $metadata['date']);
     // Clean non-numerics from ISBN
     $metadata['isbn'] = PKPString::regexp_replace('/[^\\dX]*/', '', $isbn);
     // Set the publicationType
     $metadata['[@publication-type]'] = NLM30_PUBLICATION_TYPE_BOOK;
     return $this->getNlm30CitationDescriptionFromMetadataArray($metadata);
 }
Esempio n. 10
0
 /**
  * Get the chapter full title (with title and subtitle).
  * @return string
  */
 function getLocalizedFullTitle()
 {
     $fullTitle = $this->getLocalizedTitle();
     if ($subtitle = $this->getLocalizedSubtitle()) {
         $fullTitle = PKPString::concatTitleFields(array($fullTitle, $subtitle));
     }
     return $fullTitle;
 }
Esempio n. 11
0
 /**
  * Query parsing helper routine.
  * Returned structure is based on that used by the Search::QueryParser Perl module.
  */
 function _parseQueryInternal($signTokens, $tokens, &$pos, $total)
 {
     $return = array('+' => array(), '' => array(), '-' => array());
     $postBool = $preBool = '';
     $submissionSearchIndex = new SubmissionSearchIndex();
     $notOperator = PKPString::strtolower(__('search.operator.not'));
     $andOperator = PKPString::strtolower(__('search.operator.and'));
     $orOperator = PKPString::strtolower(__('search.operator.or'));
     while ($pos < $total) {
         if (!empty($signTokens[$pos])) {
             $sign = $signTokens[$pos];
         } else {
             if (empty($sign)) {
                 $sign = '+';
             }
         }
         $token = PKPString::strtolower($tokens[$pos++]);
         switch ($token) {
             case $notOperator:
                 $sign = '-';
                 break;
             case ')':
                 return $return;
             case '(':
                 $token = $this->_parseQueryInternal($signTokens, $tokens, $pos, $total);
             default:
                 $postBool = '';
                 if ($pos < $total) {
                     $peek = PKPString::strtolower($tokens[$pos]);
                     if ($peek == $orOperator) {
                         $postBool = 'or';
                         $pos++;
                     } else {
                         if ($peek == $andOperator) {
                             $postBool = 'and';
                             $pos++;
                         }
                     }
                 }
                 $bool = empty($postBool) ? $preBool : $postBool;
                 $preBool = $postBool;
                 if ($bool == 'or') {
                     $sign = '';
                 }
                 if (is_array($token)) {
                     $k = $token;
                 } else {
                     $k = $submissionSearchIndex->filterKeywords($token, true);
                 }
                 if (!empty($k)) {
                     $return[$sign][] = $k;
                 }
                 $sign = '';
                 break;
         }
     }
     return $return;
 }
 /**
  * @see OAIMetadataFormat#toXml
  */
 function toXml(&$record, $format = null)
 {
     $article = $record->getData('article');
     $journal = $record->getData('journal');
     $templateMgr = TemplateManager::getManager();
     $templateMgr->assign(array('journal' => $journal, 'article' => $article, 'issue' => $record->getData('issue'), 'section' => $record->getData('section')));
     $subjects = array_merge_recursive($this->stripAssocArray((array) $article->getDiscipline(null)), $this->stripAssocArray((array) $article->getSubject(null)));
     $templateMgr->assign(array('subject' => isset($subjects[$journal->getPrimaryLocale()]) ? $subjects[$journal->getPrimaryLocale()] : '', 'abstract' => PKPString::html2text($article->getAbstract($article->getLocale())), 'language' => AppLocale::get3LetterIsoFromLocale($article->getLocale())));
     return $templateMgr->fetch(dirname(__FILE__) . '/record.tpl');
 }
 /**
  * Retrieve the export as an XML string.
  * @param $pluginUrl string the url to be requested for export.
  * @param $postParams array additional post parameters
  * @return string
  */
 protected function getXmlOnExport($pluginUrl, $postParams = array())
 {
     // Prepare HTTP session.
     $curlCh = curl_init();
     curl_setopt($curlCh, CURLOPT_POST, true);
     // Create a cookie file (required for log-in).
     $cookies = tempnam(sys_get_temp_dir(), 'curlcookies');
     // Log in.
     $loginUrl = $this->baseUrl . '/index.php/test/login/signIn';
     // Bug #8518 safety work-around
     if ($this->password[0] == '@') {
         die('CURL parameters may not begin with @.');
     }
     $loginParams = array('username' => 'admin', 'password' => $this->password);
     curl_setopt($curlCh, CURLOPT_URL, $loginUrl);
     curl_setopt($curlCh, CURLOPT_POSTFIELDS, $loginParams);
     curl_setopt($curlCh, CURLOPT_COOKIEJAR, $cookies);
     self::assertTrue(curl_exec($curlCh));
     // Request export document.
     $exportUrl = $this->baseUrl . '/index.php/test/manager/importexport/plugin/' . $pluginUrl;
     curl_setopt($curlCh, CURLOPT_URL, $exportUrl);
     // Bug #8518 safety work-around
     foreach ($postParams as $paramValue) {
         if ($paramValue[0] == '@') {
             die('CURL parameters may not begin with @.');
         }
     }
     curl_setopt($curlCh, CURLOPT_POSTFIELDS, $postParams);
     curl_setopt($curlCh, CURLOPT_HTTPHEADER, array('Accept: application/xml, application/x-gtar, */*'));
     curl_setopt($curlCh, CURLOPT_RETURNTRANSFER, true);
     curl_setopt($curlCh, CURLOPT_HEADER, true);
     $response = curl_exec($curlCh);
     do {
         list($header, $response) = explode("\r\n\r\n", $response, 2);
     } while (PKPString::regexp_match('#HTTP/.*100#', $header));
     // Check whether we got a tar file.
     if (PKPString::regexp_match('#Content-Type: application/x-gtar#', $header)) {
         // Save the data to a temporary file.
         $tempfile = tempnam(sys_get_temp_dir(), 'tst');
         file_put_contents($tempfile, $response);
         // Recursively extract tar file.
         $result = $this->extractTarFile($tempfile);
         unlink($tempfile);
     } else {
         $matches = null;
         PKPString::regexp_match_get('#filename="([^"]+)"#', $header, $matches);
         self::assertTrue(isset($matches[1]));
         $result = array($matches[1] => $response);
     }
     // Destroy HTTP session.
     curl_close($curlCh);
     unlink($cookies);
     return $result;
 }
Esempio n. 14
0
 /**
  * Get the series full title (with title and subtitle).
  * @return string
  */
 function getLocalizedFullTitle()
 {
     $fullTitle = null;
     if ($prefix = $this->getLocalizedPrefix()) {
         $fullTitle = $prefix . ' ';
     }
     $fullTitle .= $this->getLocalizedTitle();
     if ($subtitle = $this->getLocalizedSubtitle()) {
         $fullTitle = PKPString::concatTitleFields(array($fullTitle, $subtitle));
     }
     return $fullTitle;
 }
 /**
  * Extracts variables for a given column from a data element
  * so that they may be assigned to template before rendering.
  * @param $row GridRow
  * @param $column GridColumn
  * @return array
  */
 function getTemplateVarsFromRowColumn($row, $column)
 {
     $element =& $row->getData();
     $columnId = $column->getId();
     assert(!empty($columnId));
     switch ($columnId) {
         case 'url':
             return array('label' => '<a href="' . PKPString::stripUnsafeHtml($element['url']) . '" target="_blank">' . PKPString::stripUnsafeHtml($element['url']) . '</a>');
         case 'shares':
             return array('label' => $element['shares']);
     }
 }
 /**
  * Get a set of GalleryPlugin objects describing the available
  * compatible plugins in their newest versions.
  * @param $application PKPApplication
  * @param $category string Optional category name to use as filter
  * @param $search string Optional text to use as filter
  * @return array GalleryPlugin objects
  */
 function getNewestCompatible($application, $category = null, $search = null)
 {
     $doc = $this->_getDocument();
     $plugins = array();
     foreach ($doc->getElementsByTagName('plugin') as $element) {
         $plugin = $this->_compatibleFromElement($element, $application);
         // May be null if no compatible version exists; also
         // apply search filters if any supplied.
         if ($plugin && ($category == '' || $plugin->getCategory() == $category) && ($search == '' || PKPString::strpos(PKPString::strtolower(serialize($plugin)), PKPString::strtolower($search)) !== false)) {
             $plugins[] = $plugin;
         }
     }
     return $plugins;
 }
 /**
  * Extract and validate a plugin (prior to installation)
  * @param $filePath string Full path to plugin archive
  * @param $originalFileName string Original filename of plugin archive
  * @return string|null Extracted plugin path on success; null on error
  */
 function extractPlugin($filePath, $originalFileName, &$errorMsg)
 {
     $fileManager = new FileManager();
     // tar archive basename (less potential version number) must
     // equal plugin directory name and plugin files must be in a
     // directory named after the plug-in (potentially with version)
     $matches = array();
     PKPString::regexp_match_get('/^[a-zA-Z0-9]+/', basename($originalFileName, '.tar.gz'), $matches);
     $pluginShortName = array_pop($matches);
     if (!$pluginShortName) {
         $errorMsg = __('manager.plugins.invalidPluginArchive');
         $fileManager->deleteFile($filePath);
         return null;
     }
     // Create random dirname to avoid symlink attacks.
     $pluginExtractDir = dirname($filePath) . DIRECTORY_SEPARATOR . $pluginShortName . substr(md5(mt_rand()), 0, 10);
     mkdir($pluginExtractDir);
     // Test whether the tar binary is available for the export to work
     $tarBinary = Config::getVar('cli', 'tar');
     if (!empty($tarBinary) && file_exists($tarBinary)) {
         exec($tarBinary . ' -xzf ' . escapeshellarg($filePath) . ' -C ' . escapeshellarg($pluginExtractDir));
     } else {
         $errorMsg = __('manager.plugins.tarCommandNotFound');
     }
     $fileManager->deleteFile($filePath);
     if (empty($errorMsg)) {
         // Look for a directory named after the plug-in's short
         // (alphanumeric) name within the extracted archive.
         if (is_dir($tryDir = $pluginExtractDir . '/' . $pluginShortName)) {
             return $tryDir;
             // Success
         }
         // Failing that, look for a directory named after the
         // archive. (Typically also contains the version number
         // e.g. with github generated release archives.)
         PKPString::regexp_match_get('/^[a-zA-Z0-9.-]+/', basename($originalFileName, '.tar.gz'), $matches);
         if (is_dir($tryDir = $pluginExtractDir . '/' . array_pop($matches))) {
             // We found a directory named after the archive
             // within the extracted archive. (Typically also
             // contains the version number, e.g. github
             // generated release archives.)
             return $tryDir;
         }
         $errorMsg = __('manager.plugins.invalidPluginArchive');
     }
     $fileManager->rmtree($pluginExtractDir);
     return null;
 }
 /**
  * Get cell actions associated with this row/column combination
  * @param $row GridRow
  * @param $column GridColumn
  * @return array an array of LinkAction instances
  */
 function getCellActions($request, $row, $column, $position = GRID_ACTION_POSITION_DEFAULT)
 {
     assert($column->getId() == 'task');
     $templateMgr = TemplateManager::getManager($request);
     $notification = $row->getData();
     $contextDao = Application::getContextDAO();
     $context = $contextDao->getById($notification->getContextId());
     $notificationMgr = new NotificationManager();
     $router = $request->getRouter();
     $templateMgr->assign(array('notificationMgr' => $notificationMgr, 'notification' => $notification, 'context' => $context, 'notificationObjectTitle' => $this->_getTitle($notification), 'message' => PKPString::stripUnsafeHtml($notificationMgr->getNotificationMessage($request, $notification))));
     // See if we're working in a multi-context environment
     $user = $request->getUser();
     $contextDao = Application::getContextDAO();
     $contexts = $contextDao->getAvailable($user ? $user->getId() : null)->toArray();
     $templateMgr->assign('isMultiContext', count($contexts) > 1);
     return array(new LinkAction('details', new AjaxAction($router->url($request, null, null, 'markRead', null, array('redirect' => 1, 'selectedElements' => array($notification->getId())))), $templateMgr->fetch('controllers/grid/tasks/task.tpl')));
 }
Esempio n. 19
0
 /**
  * Display the form.
  */
 function display()
 {
     $templateMgr = TemplateManager::getManager($this->_request);
     $templateMgr->assign('localeOptions', $this->supportedLocales);
     $templateMgr->assign('localesComplete', $this->localesComplete);
     $templateMgr->assign('clientCharsetOptions', $this->supportedClientCharsets);
     $templateMgr->assign('connectionCharsetOptions', $this->supportedConnectionCharsets);
     $templateMgr->assign('databaseCharsetOptions', $this->supportedDatabaseCharsets);
     $templateMgr->assign('allowFileUploads', get_cfg_var('file_uploads') ? __('common.yes') : __('common.no'));
     $templateMgr->assign('maxFileUploadSize', get_cfg_var('upload_max_filesize'));
     $templateMgr->assign('databaseDriverOptions', $this->checkDBDrivers());
     $templateMgr->assign('supportsMBString', PKPString::hasMBString() ? __('common.yes') : __('common.no'));
     $templateMgr->assign('phpIsSupportedVersion', version_compare(PHP_REQUIRED_VERSION, PHP_VERSION) != 1);
     import('lib.pkp.classes.xslt.XSLTransformer');
     $templateMgr->assign('xslEnabled', XSLTransformer::checkSupport());
     $templateMgr->assign('xslRequired', REQUIRES_XSL);
     $templateMgr->assign('phpRequiredVersion', PHP_REQUIRED_VERSION);
     $templateMgr->assign('phpVersion', PHP_VERSION);
     parent::display();
 }
 /**
  * @see Filter::process()
  * @param $input string
  * @return mixed array
  */
 function &process(&$input)
 {
     // The default implementation assumes that raw citations are
     // separated with line endings.
     // 1) Remove empty lines and normalize line endings.
     $input = PKPString::regexp_replace('/[\\r\\n]+/s', "\n", $input);
     // 2) Remove trailing/leading line breaks.
     $input = trim($input, "\n");
     // 3) Break up at line endings.
     if (empty($input)) {
         $citations = array();
     } else {
         $citations = explode("\n", $input);
     }
     // 4) Remove numbers from the beginning of each citation.
     foreach ($citations as $index => $citation) {
         $citations[$index] = PKPString::regexp_replace('/^\\s*[\\[#]?[0-9]+[.)\\]]?\\s*/', '', $citation);
     }
     return $citations;
 }
 /**
  * @copydoc NotificationManagerDelegate::getNotificationMessage()
  */
 public function getNotificationMessage($request, $notification)
 {
     assert($notification->getAssocType() == ASSOC_TYPE_QUERY);
     $queryDao = DAORegistry::getDAO('QueryDAO');
     $query = $queryDao->getById($notification->getAssocId());
     $headNote = $query->getHeadNote();
     assert($headNote);
     switch ($notification->getType()) {
         case NOTIFICATION_TYPE_NEW_QUERY:
             $user = $headNote->getUser();
             return __('submission.query.new', array('creatorName' => $user->getFullName(), 'noteContents' => substr(PKPString::html2text($headNote->getContents()), 0, 200), 'noteTitle' => substr($headNote->getTitle(), 0, 200)));
         case NOTIFICATION_TYPE_QUERY_ACTIVITY:
             $notes = $query->getReplies(null, NOTE_ORDER_ID, SORT_DIRECTION_DESC);
             $latestNote = $notes->next();
             $user = $latestNote->getUser();
             $notes->close();
             return __('submission.query.activity', array('responderName' => $user->getFullName(), 'noteContents' => substr(PKPString::html2text($latestNote->getContents()), 0, 200), 'noteTitle' => substr($headNote->getTitle(), 0, 200)));
         default:
             assert(false);
     }
 }
 /**
  * @covers PKPString::diff
  */
 public function testDiff()
 {
     // Test two strings that have common substrings.
     $originalString = 'The original string.';
     $editedString = 'The edited original.';
     $expectedDiff = array(array(0 => 'The'), array(1 => ' edited'), array(0 => ' original'), array(-1 => ' string'), array(0 => '.'));
     $resultDiff = PKPString::diff($originalString, $editedString);
     self::assertEquals($expectedDiff, $resultDiff);
     // Test two completely different strings.
     $originalString = 'abc';
     $editedString = 'def';
     $expectedDiff = array(array(-1 => 'abc'), array(1 => 'def'));
     $resultDiff = PKPString::diff($originalString, $editedString);
     self::assertEquals($expectedDiff, $resultDiff);
     // A more realistic example from the citation editor use case
     $originalString = 'Willinsky, B. (2006). The access principle: The case for open acces to research and scholarship. Cambridge, MA: MIT Press.';
     $editedString = 'Willinsky, J. (2006). The access principle: The case for open access to research and scholarship. Cambridge, MA: MIT Press.';
     $expectedDiff = array(array(0 => 'Willinsky, '), array(-1 => 'B'), array(1 => 'J'), array(0 => '. (2006). The access principle: The case for open acce'), array(1 => 's'), array(0 => 's to research and scholarship. Cambridge, MA: MIT Press.'));
     $resultDiff = PKPString::diff($originalString, $editedString);
     self::assertEquals($expectedDiff, $resultDiff);
 }
Esempio n. 23
0
    /**
     * Retrieve all published authors for a press in an associative array by
     * the first letter of the last name, for example:
     * $returnedArray['S'] gives array($misterSmithObject, $misterSmytheObject, ...)
     * Keys will appear in sorted order. Note that if pressId is null,
     * alphabetized authors for all presses are returned.
     * @param $pressId int
     * @param $initial An initial the last names must begin with
     * @return array Authors ordered by sequence
     */
    function getAuthorsAlphabetizedByPress($pressId = null, $initial = null, $rangeInfo = null)
    {
        $params = array('affiliation', AppLocale::getPrimaryLocale(), 'affiliation', AppLocale::getLocale());
        if (isset($pressId)) {
            $params[] = $pressId;
        }
        if (isset($initial)) {
            $params[] = PKPString::strtolower($initial) . '%';
            $initialSql = ' AND LOWER(a.last_name) LIKE LOWER(?)';
        } else {
            $initialSql = '';
        }
        $result = $this->retrieveRange('SELECT DISTINCT
				CAST(\'\' AS CHAR) AS url,
				a.author_id AS author_id,
				a.submission_id AS submission_id,
				CAST(\'\' AS CHAR) AS email,
				0 AS primary_contact,
				0 AS seq,
				a.first_name AS first_name,
				a.middle_name AS middle_name,
				a.last_name AS last_name,
				asl.setting_value AS affiliation_l,
				asl.locale,
				aspl.setting_value AS affiliation_pl,
				aspl.locale AS primary_locale,
				a.suffix AS suffix,
				a.user_group_id AS user_group_id,
				a.include_in_browse AS include_in_browse,
				0 AS show_title,
				a.country
			FROM	authors a
				LEFT JOIN author_settings aspl ON (a.author_id = aspl.author_id AND aspl.setting_name = ? AND aspl.locale = ?)
				LEFT JOIN author_settings asl ON (a.author_id = asl.author_id AND asl.setting_name = ? AND asl.locale = ?)
				JOIN submissions s ON (a.submission_id = s.submission_id)
			WHERE	s.status = ' . STATUS_PUBLISHED . ' ' . (isset($pressId) ? 'AND s.context_id = ? ' : '') . '
				AND (a.last_name IS NOT NULL AND a.last_name <> \'\')' . $initialSql . '
			ORDER BY a.last_name, a.first_name', $params, $rangeInfo);
        return new DAOResultFactory($result, $this, '_fromRow');
    }
Esempio n. 24
0
 /**
  * Display user login form.
  * Redirect to user index page if user is already validated.
  */
 function index($args, $request)
 {
     $this->setupTemplate($request);
     if (Validation::isLoggedIn()) {
         $this->sendHome($request);
     }
     if (Config::getVar('security', 'force_login_ssl') && $request->getProtocol() != 'https') {
         // Force SSL connections for login
         $request->redirectSSL();
     }
     $sessionManager = SessionManager::getManager();
     $session = $sessionManager->getUserSession();
     $templateMgr = TemplateManager::getManager($request);
     $templateMgr->assign(array('loginMessage' => $request->getUserVar('loginMessage'), 'username' => $session->getSessionVar('username'), 'remember' => $request->getUserVar('remember'), 'source' => $request->getUserVar('source'), 'showRemember' => Config::getVar('general', 'session_lifetime') > 0));
     // For force_login_ssl with base_url[...]: make sure SSL used for login form
     $loginUrl = $this->_getLoginUrl($request);
     if (Config::getVar('security', 'force_login_ssl')) {
         $loginUrl = PKPString::regexp_replace('/^http:/', 'https:', $loginUrl);
     }
     $templateMgr->assign('loginUrl', $loginUrl);
     $templateMgr->display('frontend/pages/userLogin.tpl');
 }
 /**
  * @see FormValidator::isValid()
  * Value is valid if it is empty and optional or meets the specified length requirements.
  * @return boolean
  */
 function isValid()
 {
     if ($this->isEmptyAndOptional()) {
         return true;
     } else {
         $length = PKPString::strlen($this->getFieldValue());
         switch ($this->_comparator) {
             case '==':
                 return $length == $this->_length;
             case '!=':
                 return $length != $this->_length;
             case '<':
                 return $length < $this->_length;
             case '>':
                 return $length > $this->_length;
             case '<=':
                 return $length <= $this->_length;
             case '>=':
                 return $length >= $this->_length;
         }
         return false;
     }
 }
 /**
  * Normalize incoming date string.
  * @see Filter::process()
  * @param $input string
  * @return string
  */
 function &process(&$input)
 {
     // FIXME: We have to i18nize this when expanding citation parsing to other languages
     static $monthNames = array('Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12');
     $dateExpressions = array('/(?P<year>\\d{4})-(?P<month>\\d{2})-(?P<day>\\d{2})/', '/(?P<year>\\d{4})(\\s|-)*(?P<monthName>[a-z]\\w+)?(\\s|-)*(?P<day>\\d+)?/i');
     $normalizedDate = null;
     foreach ($dateExpressions as $dateExpression) {
         if (PKPString::regexp_match_get($dateExpression, $input, $parsedDate)) {
             if (isset($parsedDate['year'])) {
                 $normalizedDate = $parsedDate['year'];
                 $month = '';
                 if (isset($parsedDate['monthName'])) {
                     $monthName = substr($parsedDate['monthName'], 0, 3);
                     if (isset($monthNames[$monthName])) {
                         // Convert the month name to a two digit numeric month representation.
                         $month = $monthNames[$monthName];
                     }
                 }
                 if (isset($parsedDate['month'])) {
                     // Convert month to a two digit representation.
                     $month = str_pad($parsedDate['month'], 2, '0', STR_PAD_LEFT);
                 }
                 if (!empty($month)) {
                     $normalizedDate .= '-' . $month;
                     if (isset($parsedDate['day'])) {
                         $normalizedDate .= '-' . str_pad($parsedDate['day'], 2, '0', STR_PAD_LEFT);
                     }
                 }
             }
             if (!empty($normalizedDate)) {
                 break;
             }
         }
     }
     return $normalizedDate;
 }
 /**
  * @verbatim
  * Helper method that configures and optionally
  * installs a filter based on the given XML node
  * which represents a <filter> element.
  * @endverbatim
  * @param $filterNode XMLNode
  * @param $persist boolean whether to install the filter
  * @return PersistableFilter the installed filter.
  */
 function &configureFilter($filterNode, $persist = true)
 {
     // Install filters.
     $filterDao = DAORegistry::getDAO('FilterDAO');
     /* @var $filterDao FilterDAO */
     $filterGroupSymbolic = $filterNode->getAttribute('inGroup');
     $filterClassName = $filterNode->getAttribute('class');
     $isTemplate = $filterNode->getAttribute('isTemplate');
     // We have to include the filter class before going on
     // so that all required constants are defined before they
     // might be used in settings.
     if (PKPString::regexp_match('/^[a-zA-Z0-9.]+$/', $filterClassName)) {
         import($filterClassName);
     }
     // Go through the filter sub-nodes. This can be nested
     // filters or filter settings.
     $subNodes = $filterNode->getChildren();
     $settings = array();
     $subFilters = array();
     foreach ($subNodes as $subNode) {
         /* @var $subNode XMLNode */
         switch ($subNode->getName()) {
             case 'setting':
                 // Get the filter setting.
                 list($name, $value) = $this->getFilterSetting($subNode);
                 $settings[$name] = $value;
                 unset($name, $value);
                 break;
             case 'filter':
                 // Recursively configure sub-filters.
                 $subFilter =& $this->configureFilter($subNode, false);
                 $subFilters[] =& $subFilter;
                 unset($subFilter);
                 break;
         }
     }
     // We ensure idempotence of plug-in installation by checking
     // for existing identical filters.
     $similarFilterFactory =& $filterDao->getObjectsByGroupAndClass($filterGroupSymbolic, $filterClassName, 0, $isTemplate);
     if ($similarFilterFactory->getCount() > 0) {
         // 1) Find similar filters.
         $similarFilters =& $similarFilterFactory->toArray();
         // 2) Go through similar filters and eliminate them
         //    if they don't have the exact same settings.
         foreach ($similarFilters as $index => $similarFilter) {
             /* @var $similarFilter PersistableFilter */
             if (!$this->compareFilters($similarFilter, $settings, $subFilters)) {
                 unset($similarFilters[$index]);
             }
         }
         // There can be a maximum of exactly one identical transformation
         // in the database otherwise we've somehow installed a duplicate filter.
         $identicalFilters = count($similarFilters);
         assert($identicalFilters <= 1);
         // 3) If the filter has been installed before then return the existing filter.
         if ($identicalFilters) {
             $existingFilter = array_pop($similarFilters);
             return $existingFilter;
         }
     }
     // Configure (and optionally install) the filter.
     $installedFilter = $filterDao->configureObject($filterClassName, $filterGroupSymbolic, $settings, $isTemplate, 0, $subFilters, $persist);
     assert(is_a($installedFilter, 'PersistableFilter'));
     return $installedFilter;
 }
 /**
  * @see Validator::isValid()
  * @param $value mixed
  * @return boolean
  */
 function isValid($value)
 {
     return (bool) PKPString::regexp_match_get($this->_regExp, $value, $this->_matches);
 }
Esempio n. 29
0
    /**
     * Retrieve all published authors for a journal in an associative array by
     * the first letter of the last name, for example:
     * $returnedArray['S'] gives array($misterSmithObject, $misterSmytheObject, ...)
     * Keys will appear in sorted order. Note that if journalId is null,
     * alphabetized authors for all enabled journals are returned.
     * @param $journalId int Optional journal ID to restrict results to
     * @param $initial An initial the last names must begin with
     * @param $rangeInfo Range information
     * @param $includeEmail Whether or not to include the email in the select distinct
     * @return DAOResultFactory Authors ordered by sequence
     */
    function getAuthorsAlphabetizedByJournal($journalId = null, $initial = null, $rangeInfo = null, $includeEmail = false)
    {
        $params = array('affiliation', AppLocale::getPrimaryLocale(), 'affiliation', AppLocale::getLocale());
        if (isset($journalId)) {
            $params[] = $journalId;
        }
        if (isset($initial)) {
            $params[] = PKPString::strtolower($initial) . '%';
            $initialSql = ' AND LOWER(aa.last_name) LIKE LOWER(?)';
        } else {
            $initialSql = '';
        }
        $result = $this->retrieveRange('SELECT DISTINCT
				CAST(\'\' AS CHAR) AS url,
				0 AS author_id,
				0 AS submission_id,
				' . ($includeEmail ? 'aa.email AS email,' : 'CAST(\'\' AS CHAR) AS email,') . '
				0 AS primary_contact,
				0 AS seq,
				aa.first_name,
				aa.middle_name,
				aa.last_name,
				SUBSTRING(asl.setting_value FROM 1 FOR 255) AS affiliation_l,
				asl.locale,
				SUBSTRING(aspl.setting_value FROM 1 FOR 255) AS affiliation_pl,
				aspl.locale AS primary_locale,
				aa.country
			FROM	authors aa
				LEFT JOIN author_settings aspl ON (aa.author_id = aspl.author_id AND aspl.setting_name = ? AND aspl.locale = ?)
				LEFT JOIN author_settings asl ON (aa.author_id = asl.author_id AND asl.setting_name = ? AND asl.locale = ?)
				JOIN submissions a ON (a.submission_id = aa.submission_id AND a.status = ' . STATUS_PUBLISHED . ')
				JOIN journals j ON (a.context_id = j.journal_id)
				JOIN published_submissions pa ON (pa.submission_id = a.submission_id)
				JOIN issues i ON (pa.issue_id = i.issue_id AND i.published = 1)
			WHERE ' . (isset($journalId) ? 'j.journal_id = ?' : 'j.enabled = 1') . '
				AND (aa.last_name IS NOT NULL AND aa.last_name <> \'\')' . $initialSql . '
			ORDER BY aa.last_name, aa.first_name', $params, $rangeInfo);
        return new DAOResultFactory($result, $this, '_returnSimpleAuthorFromRow');
    }
Esempio n. 30
0
 /**
  * @see OAIMetadataFormat#toXml
  * TODO:
  *  <copyright-holder>
  *  In Isabelle's mapping document:
  *   Article order in the issue's Table of Contents
  */
 function toXml(&$record, $format = null)
 {
     $article =& $record->getData('article');
     $journal =& $record->getData('journal');
     $section =& $record->getData('section');
     $issue =& $record->getData('issue');
     $galleys =& $record->getData('galleys');
     $articleId = $article->getId();
     // Cache issue ordering information.
     static $issueId;
     static $sectionSeq;
     if (!isset($issueId) || $issueId != $issue->getId()) {
         $sectionDao = DAORegistry::getDAO('SectionDAO');
         $issueId = $issue->getId();
         $sections = $sectionDao->getByIssueId($issueId);
         $sectionSeq = array();
         $i = 0;
         foreach ($sections as $thisSection) {
             $sectionSeq[$thisSection->getId()] = $i++;
         }
         unset($sections);
     }
     $abbreviation = $journal->getLocalizedSetting('abbreviation');
     $printIssn = $journal->getSetting('printIssn');
     $onlineIssn = $journal->getSetting('onlineIssn');
     $primaryLocale = $article->getLanguage() != '' ? $article->getLanguage() : $journal->getPrimaryLocale();
     $publisherInstitution = $journal->getSetting('publisherInstitution');
     $datePublished = $article->getDatePublished();
     if (!$datePublished) {
         $datePublished = $issue->getDatePublished();
     }
     if ($datePublished) {
         $datePublished = strtotime($datePublished);
     }
     $response = "<article\n" . "\txmlns=\"http://dtd.nlm.nih.gov/publishing/2.3\"\n" . "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n" . "\txmlns:mml=\"http://www.w3.org/1998/Math/MathML\"\n" . "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" . "\txsi:schemaLocation=\"http://dtd.nlm.nih.gov/publishing/2.3\n" . "\thttp://dtd.nlm.nih.gov/publishing/2.3/xsd/journalpublishing.xsd\"\n" . (($s = $section->getLocalizedIdentifyType()) != '' ? "\tarticle-type=\"" . htmlspecialchars(Core::cleanVar($s)) . "\"" : '') . "\txml:lang=\"" . strtoupper(substr($primaryLocale, 0, 2)) . "\">\n" . "\t<front>\n" . "\t\t<journal-meta>\n" . "\t\t\t<journal-id journal-id-type=\"other\">" . htmlspecialchars(Core::cleanVar(($s = Config::getVar('oai', 'nlm_journal_id')) != '' ? $s : $journal->getPath())) . "</journal-id>\n" . "\t\t\t<journal-title>" . htmlspecialchars(Core::cleanVar($journal->getLocalizedName())) . "</journal-title>\n";
     // Include translated journal titles
     foreach ($journal->getName(null) as $locale => $title) {
         if ($locale == $primaryLocale) {
             continue;
         }
         $response .= "\t\t\t<trans-title xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">" . htmlspecialchars(Core::cleanVar($title)) . "</trans-title>\n";
     }
     $response .= (!empty($onlineIssn) ? "\t\t\t<issn pub-type=\"epub\">" . htmlspecialchars(Core::cleanVar($onlineIssn)) . "</issn>" : '') . (!empty($printIssn) ? "\t\t\t<issn pub-type=\"ppub\">" . htmlspecialchars(Core::cleanVar($printIssn)) . "</issn>" : '') . ($publisherInstitution != '' ? "\t\t\t<publisher><publisher-name>" . htmlspecialchars(Core::cleanVar($publisherInstitution)) . "</publisher-name></publisher>\n" : '') . "\t\t</journal-meta>\n" . "\t\t<article-meta>\n" . "\t\t\t<article-id pub-id-type=\"other\">" . htmlspecialchars(Core::cleanVar($article->getBestArticleId())) . "</article-id>\n" . (($s = $article->getPubId('doi')) ? "\t\t\t<article-id pub-id-type=\"doi\">" . htmlspecialchars(Core::cleanVar($s)) . "</article-id>\n" : '') . "\t\t\t<article-categories><subj-group subj-group-type=\"heading\"><subject>" . htmlspecialchars(Core::cleanVar($section->getLocalizedTitle())) . "</subject></subj-group></article-categories>\n" . "\t\t\t<title-group>\n" . "\t\t\t\t<article-title>" . htmlspecialchars(Core::cleanVar(strip_tags($article->getLocalizedTitle()))) . "</article-title>\n";
     // Include translated journal titles
     foreach ($article->getTitle(null) as $locale => $title) {
         if ($locale == $primaryLocale) {
             continue;
         }
         $response .= "\t\t\t\t<trans-title xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">" . htmlspecialchars(Core::cleanVar(strip_tags($title))) . "</trans-title>\n";
     }
     $response .= "\t\t\t</title-group>\n" . "\t\t\t<contrib-group>\n";
     // Include authors
     foreach ($article->getAuthors() as $author) {
         $response .= "\t\t\t\t<contrib " . ($author->getPrimaryContact() ? 'corresp="yes" ' : '') . "contrib-type=\"author\">\n" . "\t\t\t\t\t<name name-style=\"western\">\n" . "\t\t\t\t\t\t<surname>" . htmlspecialchars(Core::cleanVar($author->getLastName())) . "</surname>\n" . "\t\t\t\t\t\t<given-names>" . htmlspecialchars(Core::cleanVar($author->getFirstName()) . (($s = $author->getMiddleName()) != '' ? " {$s}" : '')) . "</given-names>\n" . "\t\t\t\t\t</name>\n" . (($s = $author->getLocalizedAffiliation()) != '' ? "\t\t\t\t\t<aff>" . htmlspecialchars(Core::cleanVar($s)) . "</aff>\n" : '') . "\t\t\t\t\t<email>" . htmlspecialchars(Core::cleanVar($author->getEmail())) . "</email>\n" . (($s = $author->getUrl()) != '' ? "\t\t\t\t\t<uri>" . htmlspecialchars(Core::cleanVar($s)) . "</uri>\n" : '') . "\t\t\t\t</contrib>\n";
     }
     // Include editorships (optimized)
     $response .= $this->getEditorialInfo($journal->getId());
     $response .= "\t\t\t</contrib-group>\n";
     if ($datePublished) {
         $response .= "\t\t\t<pub-date pub-type=\"epub\">\n" . "\t\t\t\t<day>" . strftime('%d', $datePublished) . "</day>\n" . "\t\t\t\t<month>" . strftime('%m', $datePublished) . "</month>\n" . "\t\t\t\t<year>" . strftime('%Y', $datePublished) . "</year>\n" . "\t\t\t</pub-date>\n";
     }
     $response .= ($issue->getShowYear() ? "\t\t\t<pub-date pub-type=\"collection\"><year>" . htmlspecialchars(Core::cleanVar($issue->getYear())) . "</year></pub-date>\n" : '') . ($issue->getShowVolume() ? "\t\t\t<volume>" . htmlspecialchars(Core::cleanVar($issue->getVolume())) . "</volume>\n" : '') . ($issue->getShowNumber() ? "\t\t\t<issue seq=\"" . htmlspecialchars(Core::cleanVar($sectionSeq[$section->getId()] * 100 + $article->getSequence())) . "\">" . htmlspecialchars(Core::cleanVar($issue->getNumber())) . "</issue>\n" : '') . "\t\t\t<issue-id pub-id-type=\"other\">" . htmlspecialchars(Core::cleanVar($issue->getBestIssueId())) . "</issue-id>\n" . ($issue->getShowTitle() ? "\t\t\t<issue-title>" . htmlspecialchars(Core::cleanVar($issue->getLocalizedTitle())) . "</issue-title>\n" : '');
     // Include page info, if available and parseable.
     $matches = null;
     if (PKPString::regexp_match_get('/^[Pp][Pp]?[.]?[ ]?(\\d+)$/', $article->getPages(), $matches)) {
         $matchedPage = htmlspecialchars(Core::cleanVar($matches[1]));
         $response .= "\t\t\t\t<fpage>{$matchedPage}</fpage><lpage>{$matchedPage}</lpage>\n";
         $pageCount = 1;
     } elseif (PKPString::regexp_match_get('/^[Pp][Pp]?[.]?[ ]?(\\d+)[ ]?(-|–)[ ]?([Pp][Pp]?[.]?[ ]?)?(\\d+)$/', $article->getPages(), $matches)) {
         $matchedPageFrom = htmlspecialchars(Core::cleanVar($matches[1]));
         $matchedPageTo = htmlspecialchars(Core::cleanVar($matches[4]));
         $response .= "\t\t\t\t<fpage>{$matchedPageFrom}</fpage>\n" . "\t\t\t\t<lpage>{$matchedPageTo}</lpage>\n";
         $pageCount = $matchedPageTo - $matchedPageFrom + 1;
     }
     $response .= "\t\t\t<permissions>\n" . "\t\t\t\t<copyright-statement>" . htmlspecialchars(__('submission.copyrightStatement', array('copyrightYear' => $article->getCopyrightYear(), 'copyrightHolder' => $article->getLocalizedCopyrightHolder()))) . "</copyright-statement>\n" . ($datePublished ? "\t\t\t\t<copyright-year>" . $article->getCopyrightYear() . "</copyright-year>\n" : '') . "\t\t\t\t<license xlink:href=\"" . $article->getLicenseURL() . "\">\n" . (($s = Application::getCCLicenseBadge($article->getLicenseURL())) ? "\t\t\t\t\t<license-p>" . strip_tags($s) . "</license-p>\n" : '') . "\t\t\t\t</license>\n" . "\t\t\t</permissions>\n" . "\t\t\t<self-uri xlink:href=\"" . htmlspecialchars(Core::cleanVar(Request::url($journal->getPath(), 'article', 'view', $article->getBestArticleId()))) . "\" />\n";
     // Include galley links
     foreach ($article->getGalleys() as $galley) {
         $response .= "\t\t\t<self-uri content-type=\"" . htmlspecialchars(Core::cleanVar($galley->getFileType())) . "\" xlink:href=\"" . htmlspecialchars(Core::cleanVar(Request::url($journal->getPath(), 'article', 'view', array($article->getBestArticleId(), $galley->getId())))) . "\" />\n";
     }
     // Include abstract(s)
     $abstract = htmlspecialchars(Core::cleanVar(strip_tags($article->getLocalizedAbstract())));
     if (!empty($abstract)) {
         $abstract = "<p>{$abstract}</p>";
         // $abstract = '<p>' . PKPString::regexp_replace('/\n+/', '</p><p>', $abstract) . '</p>';
         $response .= "\t\t\t<abstract xml:lang=\"" . strtoupper(substr($primaryLocale, 0, 2)) . "\">{$abstract}</abstract>\n";
     }
     if (is_array($article->getAbstract(null))) {
         foreach ($article->getAbstract(null) as $locale => $abstract) {
             if ($locale == $primaryLocale || empty($abstract)) {
                 continue;
             }
             $abstract = htmlspecialchars(Core::cleanVar(strip_tags($abstract)));
             if (empty($abstract)) {
                 continue;
             }
             $abstract = "<p>{$abstract}</p>";
             //$abstract = '<p>' . PKPString::regexp_replace('/\n+/', '</p><p>', $abstract) . '</p>';
             $response .= "\t\t\t<abstract-trans xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">{$abstract}</abstract-trans>\n";
         }
     }
     $subjects = array();
     if (is_array($article->getSubject(null))) {
         foreach ($article->getSubject(null) as $locale => $subject) {
             $s = array_map('trim', explode(';', Core::cleanVar($subject)));
             if (!empty($s)) {
                 $subjects[$locale] = $s;
             }
         }
     }
     if (!empty($subjects)) {
         foreach ($subjects as $locale => $s) {
             $response .= "\t\t\t<kwd-group xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">\n";
             foreach ($s as $subject) {
                 $response .= "\t\t\t\t<kwd>" . htmlspecialchars($subject) . "</kwd>\n";
             }
             $response .= "\t\t\t</kwd-group>\n";
         }
     }
     $response .= (isset($pageCount) ? "\t\t\t<counts><page-count count=\"" . (int) $pageCount . "\" /></counts>\n" : '') . "\t\t</article-meta>\n" . "\t</front>\n";
     // Include body text (for search indexing only)
     import('classes.search.ArticleSearchIndex');
     $text = '';
     $galleys = $article->getGalleys();
     // Give precedence to HTML galleys, as they're quickest to parse
     usort($galleys, create_function('$a, $b', 'return $a->getFileType()==\'text/html\')?-1:1;'));
     // Determine any access limitations. If there are, do not
     // provide the full-text.
     import('classes.issue.IssueAction');
     $issueAction = new IssueAction();
     $subscriptionRequired = $issueAction->subscriptionRequired($issue);
     $isSubscribedDomain = $issueAction->subscribedDomain($journal, $issue->getId(), $article->getId());
     if (!$subscriptionRequired || $isSubscribedDomain) {
         foreach ($galleys as $galley) {
             $parser =& SearchFileParser::fromFile($galley);
             if ($parser && $parser->open()) {
                 while (($s = $parser->read()) !== false) {
                     $text .= $s;
                 }
                 $parser->close();
             }
             if ($galley->getFileType() == 'text/html') {
                 $text = strip_tags($text);
             }
             unset($galley);
             // Use the first parseable galley.
             if (!empty($text)) {
                 break;
             }
         }
     }
     if (!empty($text)) {
         $response .= "\t<body><p>" . htmlspecialchars(Core::cleanVar(Core::cleanVar($text))) . "</p></body>\n";
     }
     // Add NLM citation info
     $filterDao = DAORegistry::getDAO('FilterDAO');
     /* @var $filterDao FilterDAO */
     $nlmFilters = $filterDao->getObjectsByGroup('submission=>nlm23-article-xml');
     assert(count($nlmFilters) == 1);
     $nlmFilter = array_pop($nlmFilters);
     $nlmXmlDom = new DOMDocument();
     $nlmXmlDom->loadXML($nlmFilter->execute($article));
     $documentElement =& $nlmXmlDom->documentElement;
     // Work-around for hasChildNodes being stupid about whitespace.
     $hasChildren = false;
     if (isset($documentElement->childNodes)) {
         foreach ($documentElement->childNodes as $c) {
             if ($c->nodeType == XML_ELEMENT_NODE) {
                 $hasChildren = true;
             }
         }
     }
     // If there were any citations, include them.
     if ($hasChildren) {
         $innerXml = $nlmXmlDom->saveXML($documentElement);
         $response .= "<back>{$innerXml}</back>\n";
     }
     $response .= "</article>";
     return $response;
 }