checks:
php:
code_rating: true
+
+# use the new PHP analysis engine
+# https://scrutinizer-ci.com/docs/tools/php/php-analyzer/guides/migrate_to_new_php_analysis
+build:
+ nodes:
+ analysis:
+ tests:
+ override:
+ - php-scrutinizer-run
+
+ dependencies:
+ override:
+ - npm install -g 'yarn'
+ - yarn install --force
+ - COMPOSER_MEMORY_LIMIT=-1 composer install -o --no-interaction --no-progress --prefer-dist
- php: 7.0
env: CS_FIXER=run VALIDATE_TRANSLATION_FILE=run ASSETS=build DB=sqlite
allow_failures:
- - php: 7.2
- php: nightly
# exclude v1 branches
}
// Just in case...
- if (count($ids) > 0) {
+ if (\count($ids) > 0) {
// Merge tags
$this->addSql('
UPDATE ' . $this->getTable('entry_tag') . '
ARG timezone='Europe/Paris'
RUN apt-get update && apt-get install -y \
- libmcrypt-dev libicu-dev libpq-dev libxml2-dev libpng12-dev libjpeg-dev \
+ libmcrypt-dev libicu-dev libpq-dev libxml2-dev libpng-dev libjpeg-dev \
&& /usr/local/bin/docker-php-ext-configure gd --with-jpeg-dir=/usr/include \
&& docker-php-ext-install \
- iconv mcrypt mbstring intl pdo pdo_mysql pdo_pgsql gd
+ iconv mbstring intl pdo pdo_mysql pdo_pgsql gd
RUN echo "date.timezone="$timezone > /usr/local/etc/php/conf.d/date_timezone.ini
{
"name": "wallabag",
- "version": "2.2.2",
+ "version": "2.3.3",
"description": "wallabag is a self hostable application for saving web pages",
"private": true,
"directories": {
"doc": "docs"
},
"engines": {
- "node": ">4.8"
+ "node": ">=6.10"
},
"repository": {
"type": "git",
#! /usr/bin/env bash
# You can execute this file to create a new package for wallabag
-# eg: `sh release.sh master /tmp wllbg-release prod`
+# eg: `sh release.sh 2.3.3 /tmp wllbg-release prod`
VERSION=$1
TMP_FOLDER=$2
rm -rf $TMP_FOLDER/$RELEASE_FOLDER
mkdir $TMP_FOLDER/$RELEASE_FOLDER
git clone git@github.com:wallabag/wallabag.git -b $VERSION $TMP_FOLDER/$RELEASE_FOLDER/$VERSION
-cd $TMP_FOLDER/$RELEASE_FOLDER/$VERSION && SYMFONY_ENV=$ENV composer up -n --no-dev
+cd $TMP_FOLDER/$RELEASE_FOLDER/$VERSION && SYMFONY_ENV=$ENV COMPOSER_MEMORY_LIMIT=-1 composer up -n --no-dev
cd $TMP_FOLDER/$RELEASE_FOLDER/$VERSION && php bin/console wallabag:install --env=$ENV
cd $TMP_FOLDER/$RELEASE_FOLDER/$VERSION && php bin/console assets:install --env=$ENV --symlink --relative
cd $TMP_FOLDER/$RELEASE_FOLDER && tar czf wallabag-$VERSION.tar.gz --exclude="var/cache/*" --exclude="var/logs/*" --exclude="var/sessions/*" --exclude=".git" $VERSION
echo "MD5 checksum of the package for wallabag $VERSION"
md5 $TMP_FOLDER/$RELEASE_FOLDER/wallabag-$VERSION.tar.gz
-scp $TMP_FOLDER/$RELEASE_FOLDER/wallabag-$VERSION.tar.gz framasoft_bag@78.46.248.87:/var/www/framabag.org/web
-rm -rf $TMP_FOLDER/$RELEASE_FOLDER
+echo "Package to upload to the release server:"
+echo $TMP_FOLDER/$RELEASE_FOLDER/wallabag-$VERSION.tar.gz
->getDoctrine()
->getRepository('WallabagAnnotationBundle:Annotation')
->findAnnotationsByPageId($entry->getId(), $this->getUser()->getId());
- $total = count($annotationRows);
+ $total = \count($annotationRows);
$annotations = ['total' => $total, 'rows' => $annotationRows];
$json = $this->get('jms_serializer')->serialize($annotations, 'json');
public function getBuilderForAllByUser($userId)
{
return $this
- ->getBuilderByUser($userId)
+ ->getSortedQueryBuilderByUser($userId)
;
}
*
* @return QueryBuilder
*/
- private function getBuilderByUser($userId)
+ private function getSortedQueryBuilderByUser($userId)
{
return $this->createQueryBuilder('a')
->leftJoin('a.user', 'u')
$order = $request->query->get('order', 'desc');
$page = (int) $request->query->get('page', 1);
$perPage = (int) $request->query->get('perPage', 30);
- $tags = is_array($request->query->get('tags')) ? '' : (string) $request->query->get('tags', '');
+ $tags = \is_array($request->query->get('tags')) ? '' : (string) $request->query->get('tags', '');
$since = $request->query->get('since', 0);
/** @var \Pagerfanta\Pagerfanta $pager */
$limit = $this->container->getParameter('wallabag_core.api_limit_mass_actions');
- if (count($urls) > $limit) {
+ if (\count($urls) > $limit) {
throw new HttpException(400, 'API limit reached');
}
'open_graph' => [
'og_image' => !empty($data['picture']) ? $data['picture'] : $entry->getPreviewPicture(),
],
- 'authors' => is_string($data['authors']) ? explode(',', $data['authors']) : $entry->getPublishedBy(),
+ 'authors' => \is_string($data['authors']) ? explode(',', $data['authors']) : $entry->getPublishedBy(),
]
);
} catch (\Exception $e) {
$contentProxy->updateLanguage($entry, $data['language']);
}
- if (!empty($data['authors']) && is_string($data['authors'])) {
+ if (!empty($data['authors']) && \is_string($data['authors'])) {
$entry->setPublishedBy(explode(',', $data['authors']));
}
*/
private function cleanOrphanTag($tags)
{
- if (!is_array($tags)) {
+ if (!\is_array($tags)) {
$tags = [$tags];
}
$em = $this->getDoctrine()->getManager();
foreach ($tags as $tag) {
- if (0 === count($tag->getEntries())) {
+ if (0 === \count($tag->getEntries())) {
$em->remove($tag);
}
}
} else {
$users = $this->getContainer()->get('wallabag_user.user_repository')->findAll();
- $this->io->text(sprintf('Cleaning through <info>%d</info> user accounts', count($users)));
+ $this->io->text(sprintf('Cleaning through <info>%d</info> user accounts', \count($users)));
foreach ($users as $user) {
$this->io->text(sprintf('Processing user <info>%s</info>', $user->getUsername()));
$url = $this->similarUrl($entry['url']);
/* @var $entry Entry */
- if (in_array($url, $urls, true)) {
+ if (\in_array($url, $urls, true)) {
++$duplicatesCount;
$em->remove($repo->find($entry['id']));
private function similarUrl($url)
{
- if (in_array(substr($url, -1), ['/', '#'], true)) { // get rid of "/" and "#" and the end of urls
- return substr($url, 0, strlen($url));
+ if (\in_array(substr($url, -1), ['/', '#'], true)) { // get rid of "/" and "#" and the end of urls
+ return substr($url, 0, \strlen($url));
}
return $url;
->getQuery()
->getResult();
- $io->text(sprintf('Exporting <info>%d</info> entrie(s) for user <info>%s</info>...', count($entries), $user->getUserName()));
+ $io->text(sprintf('Exporting <info>%d</info> entrie(s) for user <info>%s</info>...', \count($entries), $user->getUserName()));
$filePath = $input->getArgument('filepath');
$status = '<info>OK!</info>';
$help = '';
- if (!extension_loaded($this->getContainer()->getParameter('database_driver'))) {
+ if (!\extension_loaded($this->getContainer()->getParameter('database_driver'))) {
$fulfilled = false;
$status = '<error>ERROR!</error>';
$help = 'Database driver "' . $this->getContainer()->getParameter('database_driver') . '" is not installed.';
$status = '<info>OK!</info>';
$help = '';
- if (!function_exists($functionRequired)) {
+ if (!\function_exists($functionRequired)) {
$fulfilled = false;
$status = '<error>ERROR!</error>';
$help = 'You need the ' . $functionRequired . ' function activated';
}
try {
- return in_array($databaseName, $schemaManager->listDatabases(), true);
+ return \in_array($databaseName, $schemaManager->listDatabases(), true);
} catch (\Doctrine\DBAL\Exception\DriverException $e) {
// it means we weren't able to get database list, assume the database doesn't exist
{
$schemaManager = $this->getContainer()->get('doctrine')->getManager()->getConnection()->getSchemaManager();
- return count($schemaManager->listTableNames()) > 0 ? true : false;
+ return \count($schemaManager->listTableNames()) > 0 ? true : false;
}
}
$io->success(
sprintf(
'%s/%s%s user(s) displayed.',
- count($users),
+ \count($users),
$nbUsers,
null === $input->getArgument('search') ? '' : ' (filtered)'
)
$entryRepository = $this->getContainer()->get('wallabag_core.entry_repository');
$entryIds = $entryRepository->findAllEntriesIdByUserId($userId);
- $nbEntries = count($entryIds);
+ $nbEntries = \count($entryIds);
if (!$nbEntries) {
$io->success('No entry to reload.');
$em = $this->getDoctrine()->getManager();
foreach ($tags as $tag) {
- if (0 === count($tag->getEntries())) {
+ if (0 === \count($tag->getEntries())) {
$em->remove($tag);
}
}
$em->flush();
// remove orphan tag in case no entries are associated to it
- if (0 === count($tag->getEntries())) {
+ if (0 === \count($tag->getEntries())) {
$em->remove($tag);
$em->flush();
}
$this->user = $tokenStorage->getToken() ? $tokenStorage->getToken()->getUser() : null;
- if (null === $this->user || !is_object($this->user)) {
+ if (null === $this->user || !\is_object($this->user)) {
return;
}
}
->add('domainName', TextFilterType::class, [
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
$value = $values['value'];
- if (strlen($value) <= 2 || empty($value)) {
+ if (\strlen($value) <= 2 || empty($value)) {
return;
}
$expression = $filterQuery->getExpr()->like($field, $filterQuery->getExpr()->lower($filterQuery->getExpr()->literal('%' . $value . '%')));
*/
protected function processExtraFields($extraFieldsStrings)
{
- if (!is_array($extraFieldsStrings)) {
+ if (!\is_array($extraFieldsStrings)) {
return [];
}
if ((empty($content) || false === $this->validateContent($content)) && false === $disableContentUpdate) {
$fetchedContent = $this->graby->fetchContent($url);
+ $fetchedContent['title'] = $this->sanitizeContentTitle($fetchedContent['title'], $fetchedContent['content_type']);
// when content is imported, we have information in $content
// in case fetching content goes bad, we'll keep the imported information instead of overriding them
(new LocaleConstraint())
);
- if (0 === count($errors)) {
+ if (0 === \count($errors)) {
$entry->setLanguage($value);
return;
(new UrlConstraint())
);
- if (0 === count($errors)) {
+ if (0 === \count($errors)) {
$entry->setPreviewPicture($value);
return;
$entry->setTitle($path);
}
+ /**
+ * Try to sanitize the title of the fetched content from wrong character encodings and invalid UTF-8 character.
+ *
+ * @param $title
+ * @param $contentType
+ *
+ * @return string
+ */
+ private function sanitizeContentTitle($title, $contentType)
+ {
+ if ('application/pdf' === $contentType) {
+ $title = $this->convertPdfEncodingToUTF8($title);
+ }
+
+ return $this->sanitizeUTF8Text($title);
+ }
+
+ /**
+ * If the title from the fetched content comes from a PDF, then its very possible that the character encoding is not
+ * UTF-8. This methods tries to identify the character encoding and translate the title to UTF-8.
+ *
+ * @param $title
+ *
+ * @return string (maybe contains invalid UTF-8 character)
+ */
+ private function convertPdfEncodingToUTF8($title)
+ {
+ // first try UTF-8 because its easier to detect its present/absence
+ foreach (['UTF-8', 'UTF-16BE', 'WINDOWS-1252'] as $encoding) {
+ if (mb_check_encoding($title, $encoding)) {
+ return mb_convert_encoding($title, 'UTF-8', $encoding);
+ }
+ }
+
+ return $title;
+ }
+
+ /**
+ * Remove invalid UTF-8 characters from the given string.
+ *
+ * @param string $rawText
+ *
+ * @return string
+ */
+ private function sanitizeUTF8Text($rawText)
+ {
+ if (mb_check_encoding($rawText, 'UTF-8')) {
+ return $rawText;
+ }
+
+ return iconv('UTF-8', 'UTF-8//IGNORE', $rawText);
+ }
+
/**
* Stock entry with fetched or imported content.
* Will fall back to OpenGraph data if available.
$entry->setHttpStatus($content['status']);
}
- if (!empty($content['authors']) && is_array($content['authors'])) {
+ if (!empty($content['authors']) && \is_array($content['authors'])) {
$entry->setPublishedBy($content['authors']);
}
}
// if content is an image, define it as a preview too
- if (!empty($content['content_type']) && in_array($this->mimeGuesser->guess($content['content_type']), ['jpeg', 'jpg', 'gif', 'png'], true)) {
+ if (!empty($content['content_type']) && \in_array($this->mimeGuesser->guess($content['content_type']), ['jpeg', 'jpg', 'gif', 'png'], true)) {
$this->updatePreviewPicture($entry, $content['url']);
}
*/
private function mask($value)
{
- return strlen($value) > 0 ? $value[0] . '*****' . $value[strlen($value) - 1] : 'Empty value';
+ return \strlen($value) > 0 ? $value[0] . '*****' . $value[\strlen($value) - 1] : 'Empty value';
}
}
// Must be one or more digits followed by w OR x
$pattern = "/(?:[^\"'\s]+\s*(?:\d+[wx])+)/";
preg_match_all($pattern, $srcsetAttribute, $matches);
- $srcset = call_user_func_array('array_merge', $matches);
+ $srcset = \call_user_func_array('array_merge', $matches);
$srcsetUrls = array_map(function ($src) {
return trim(explode(' ', $src, 2)[0]);
}, $srcset);
$this->logger->debug('DownloadImages: Checking extension (alternative)', ['ext' => $ext]);
}
- if (!in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) {
+ if (!\in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) {
$this->logger->error('DownloadImages: Processed image with not allowed extension. Skipping: ' . $imagePath);
return false;
*/
public function setEntries($entries)
{
- if (!is_array($entries)) {
+ if (!\is_array($entries)) {
$this->language = $entries->getLanguage();
$entries = [$entries];
}
{
$delimiter = ';';
$enclosure = '"';
- $handle = fopen('php://memory', 'rb+');
+ $handle = fopen('php://memory', 'b+r');
fputcsv($handle, ['Title', 'URL', 'Content', 'Tags', 'MIME Type', 'Language', 'Creation date'], $delimiter, $enclosure);
$user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
}
- if (null === $user || !is_object($user)) {
+ if (null === $user || !\is_object($user)) {
return;
}
{
$user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
- if (null === $user || !is_object($user)) {
+ if (null === $user || !\is_object($user)) {
return $url;
}
{
$tagsEntities = [];
- if (!is_array($tags)) {
+ if (!\is_array($tags)) {
$tags = explode(',', $tags);
}
$label = trim(mb_convert_case($label, MB_CASE_LOWER));
// avoid empty tag
- if (0 === strlen($label)) {
+ if (0 === \strlen($label)) {
continue;
}
{
// If there is no manager, this means that only Doctrine DBAL is configured
// In this case we can do nothing and just return
- if (null === $this->registry || !count($this->registry->getManagers())) {
+ if (null === $this->registry || !\count($this->registry->getManagers())) {
return false;
}
public function getBuilderForAllByUser($userId)
{
return $this
- ->getBuilderByUser($userId)
+ ->getSortedQueryBuilderByUser($userId)
;
}
public function getBuilderForUnreadByUser($userId)
{
return $this
- ->getBuilderByUser($userId)
+ ->getSortedQueryBuilderByUser($userId)
->andWhere('e.isArchived = false')
;
}
public function getBuilderForArchiveByUser($userId)
{
return $this
- ->getBuilderByUser($userId)
+ ->getSortedQueryBuilderByUser($userId)
->andWhere('e.isArchived = true')
;
}
public function getBuilderForStarredByUser($userId)
{
return $this
- ->getBuilderByUser($userId, 'starredAt', 'desc')
+ ->getSortedQueryBuilderByUser($userId, 'starredAt', 'desc')
->andWhere('e.isStarred = true')
;
}
public function getBuilderForSearchByUser($userId, $term, $currentRoute)
{
$qb = $this
- ->getBuilderByUser($userId);
+ ->getSortedQueryBuilderByUser($userId);
if ('starred' === $currentRoute) {
$qb->andWhere('e.isStarred = true');
}
/**
- * Retrieves untagged entries for a user.
+ * Retrieve a sorted list of untagged entries for a user.
*
* @param int $userId
*
public function getBuilderForUntaggedByUser($userId)
{
return $this
- ->getBuilderByUser($userId)
- ->andWhere('size(e.tags) = 0');
+ ->sortQueryBuilder($this->getRawBuilderForUntaggedByUser($userId));
+ }
+
+ /**
+ * Retrieve untagged entries for a user.
+ *
+ * @param int $userId
+ *
+ * @return QueryBuilder
+ */
+ public function getRawBuilderForUntaggedByUser($userId)
+ {
+ return $this->getQueryBuilderByUser($userId)
+ ->leftJoin('e.tags', 't')
+ ->andWhere('t.id is null');
}
/**
$qb->andWhere('e.updatedAt > :since')->setParameter('since', new \DateTime(date('Y-m-d H:i:s', $since)));
}
- if (is_string($tags) && '' !== $tags) {
+ if (\is_string($tags) && '' !== $tags) {
foreach (explode(',', $tags) as $i => $tag) {
$entryAlias = 'e' . $i;
$tagAlias = 't' . $i;
*/
public function removeTag($userId, Tag $tag)
{
- $entries = $this->getBuilderByUser($userId)
+ $entries = $this->getSortedQueryBuilderByUser($userId)
->innerJoin('e.tags', 't')
->andWhere('t.id = :tagId')->setParameter('tagId', $tag->getId())
->getQuery()
*/
public function findAllByTagId($userId, $tagId)
{
- return $this->getBuilderByUser($userId)
+ return $this->getSortedQueryBuilderByUser($userId)
->innerJoin('e.tags', 't')
->andWhere('t.id = :tagId')->setParameter('tagId', $tagId)
->getQuery()
->getQuery()
->getResult();
- if (count($res)) {
+ if (\count($res)) {
return current($res);
}
}
/**
- * Return a query builder to used by other getBuilderFor* method.
+ * Return a query builder to be used by other getBuilderFor* method.
+ *
+ * @param int $userId
+ *
+ * @return QueryBuilder
+ */
+ private function getQueryBuilderByUser($userId)
+ {
+ return $this->createQueryBuilder('e')
+ ->andWhere('e.user = :userId')->setParameter('userId', $userId);
+ }
+
+ /**
+ * Return a sorted query builder to be used by other getBuilderFor* method.
*
* @param int $userId
* @param string $sortBy
*
* @return QueryBuilder
*/
- private function getBuilderByUser($userId, $sortBy = 'createdAt', $direction = 'desc')
+ private function getSortedQueryBuilderByUser($userId, $sortBy = 'createdAt', $direction = 'desc')
{
- return $this->createQueryBuilder('e')
- ->andWhere('e.user = :userId')->setParameter('userId', $userId)
+ return $this->sortQueryBuilder($this->getQueryBuilderByUser($userId), $sortBy, $direction);
+ }
+
+ /**
+ * Return the given QueryBuilder with an orderBy() call.
+ *
+ * @param QueryBuilder $qb
+ * @param string $sortBy
+ * @param string $direction
+ *
+ * @return QueryBuilder
+ */
+ private function sortQueryBuilder(QueryBuilder $qb, $sortBy = 'createdAt', $direction = 'desc')
+ {
+ return $qb
->orderBy(sprintf('e.%s', $sortBy), $direction);
}
}
$query->setResultCacheLifetime($cacheLifeTime);
}
- return count($query->getArrayResult());
+ return \count($query->getArrayResult());
}
/**
<div class="card">
<div class="card-body">
+ <div class="card-image waves-effect waves-block waves-light">
+ <ul class="card-entry-labels">
+ {% for tag in entry.tags | slice(0, 3) %}
+ <li><a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{ tag.label }}</a></li>
+ {% endfor %}
+ </ul>
+ </div>
{% include "@WallabagCore/themes/material/Entry/Card/_content.html.twig" with {'entry': entry} only %}
</div>
*/
public static function getReadingTime($text)
{
- return floor(count(preg_split('~[^\p{L}\p{N}\']+~u', strip_tags($text))) / 200);
+ return floor(\count(preg_split('~[^\p{L}\p{N}\']+~u', strip_tags($text))) / 200);
}
}
{
$user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
- if (null === $user || !is_object($user)) {
+ if (null === $user || !\is_object($user)) {
return 0;
}
$query->useResultCache(true);
$query->setResultCacheLifetime($this->lifeTime);
- return count($query->getArrayResult());
+ return \count($query->getArrayResult());
}
/**
{
$user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
- if (null === $user || !is_object($user)) {
+ if (null === $user || !\is_object($user)) {
return 0;
}
{
$user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
- if (null === $user || !is_object($user)) {
+ if (null === $user || !\is_object($user)) {
return 0;
}
$query->useResultCache(true);
$query->setResultCacheLifetime($this->lifeTime);
- $nbArchives = count($query->getArrayResult());
+ $nbArchives = \count($query->getArrayResult());
$interval = $user->getCreatedAt()->diff(new \DateTime('now'));
$nbDays = (int) $interval->format('%a') ?: 1;
$user = $em->getRepository('WallabagUserBundle:User')->findOneByUsername($input->getArgument('username'));
}
- if (!is_object($user)) {
+ if (!\is_object($user)) {
throw new Exception(sprintf('User "%s" not found', $input->getArgument('username')));
}
$markAsRead = $form->get('mark_as_read')->getData();
$name = $this->getUser()->getId() . '.json';
- if (null !== $file && in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
+ if (null !== $file && \in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
$res = $wallabag
->setFilepath($this->getParameter('wallabag_import.resource_dir') . '/' . $name)
->setMarkAsRead($markAsRead)
$markAsRead = $form->get('mark_as_read')->getData();
$name = 'instapaper_' . $this->getUser()->getId() . '.csv';
- if (null !== $file && in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
+ if (null !== $file && \in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
$res = $instapaper
->setFilepath($this->getParameter('wallabag_import.resource_dir') . '/' . $name)
->setMarkAsRead($markAsRead)
$markAsRead = $form->get('mark_as_read')->getData();
$name = 'pinboard_' . $this->getUser()->getId() . '.json';
- if (null !== $file && in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
+ if (null !== $file && \in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
$res = $pinboard
->setFilepath($this->getParameter('wallabag_import.resource_dir') . '/' . $name)
->setMarkAsRead($markAsRead)
$markAsRead = $form->get('mark_as_read')->getData();
$name = 'readability_' . $this->getUser()->getId() . '.json';
- if (null !== $file && in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
+ if (null !== $file && \in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
$res = $readability
->setFilepath($this->getParameter('wallabag_import.resource_dir') . '/' . $name)
->setMarkAsRead($markAsRead)
$markAsRead = $form->get('mark_as_read')->getData();
$name = $this->getUser()->getId() . '.json';
- if (null !== $file && in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
+ if (null !== $file && \in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
$res = $wallabag
->setFilepath($this->getParameter('wallabag_import.resource_dir') . '/' . $name)
->setMarkAsRead($markAsRead)
*/
public function parseEntry(array $importedEntry)
{
- if ((!array_key_exists('guid', $importedEntry) || (!array_key_exists('id', $importedEntry))) && is_array(reset($importedEntry))) {
+ if ((!array_key_exists('guid', $importedEntry) || (!array_key_exists('id', $importedEntry))) && \is_array(reset($importedEntry))) {
if ($this->producer) {
$this->parseEntriesForProducer($importedEntry);
}
$entries = [];
- $handle = fopen($this->filepath, 'r');
+ $handle = fopen($this->filepath, 'rb');
while (false !== ($data = fgetcsv($handle, 10240))) {
if ('URL' === $data[0]) {
continue;
// BUT it can also be the status (since status = folder in Instapaper)
// and we don't want archive, unread & starred to become a tag
$tags = null;
- if (false === in_array($data[3], ['Archive', 'Unread', 'Starred'], true)) {
+ if (false === \in_array($data[3], ['Archive', 'Unread', 'Starred'], true)) {
$tags = [$data[3]];
}
// - first call get 5k offset 0
// - second call get 5k offset 5k
// - and so on
- if (self::NB_ELEMENTS === count($entries['list'])) {
+ if (self::NB_ELEMENTS === \count($entries['list'])) {
++$run;
return $this->import(self::NB_ELEMENTS * $run);
// In case of a bad fetch in v1, replace title and content with v2 error strings
// If fetching fails again, they will get this instead of the v1 strings
- if (in_array($entry['title'], $this->untitled, true)) {
+ if (\in_array($entry['title'], $this->untitled, true)) {
$data['title'] = $this->fetchingErrorMessageTitle;
$data['html'] = $this->fetchingErrorMessage;
}
$this->assertSame(200, $client->getResponse()->getStatusCode());
$newNbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
- $this->assertGreaterThan(count($nbClients), count($newNbClients));
+ $this->assertGreaterThan(\count($nbClients), \count($newNbClients));
$this->assertGreaterThan(1, $alert = $crawler->filter('.settings ul li strong')->extract(['_text']));
$this->assertContains('My app', $alert[0]);
$crawler = $client->request('GET', '/developer');
$this->assertSame(200, $client->getResponse()->getStatusCode());
- $this->assertSame(count($nbClients), $crawler->filter('ul[class=collapsible] li')->count());
+ $this->assertSame(\count($nbClients), $crawler->filter('ul[class=collapsible] li')->count());
}
public function testDeveloperHowto()
$this->assertSame($entry->getTitle(), $content['title']);
$this->assertSame($entry->getUrl(), $content['url']);
- $this->assertCount(count($entry->getTags()), $content['tags']);
+ $this->assertCount(\count($entry->getTags()), $content['tags']);
$this->assertSame($entry->getUserName(), $content['user_name']);
$this->assertSame($entry->getUserEmail(), $content['user_email']);
$this->assertSame($entry->getUserId(), $content['user_id']);
$content = json_decode($this->client->getResponse()->getContent(), true);
- $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertGreaterThanOrEqual(1, \count($content));
$this->assertNotEmpty($content['_embedded']['items']);
$this->assertGreaterThanOrEqual(1, $content['total']);
$this->assertSame(1, $content['page']);
$content = json_decode($this->client->getResponse()->getContent(), true);
- $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertGreaterThanOrEqual(1, \count($content));
$this->assertArrayHasKey('items', $content['_embedded']);
$this->assertGreaterThanOrEqual(0, $content['total']);
$this->assertSame(1, $content['page']);
$content = json_decode($this->client->getResponse()->getContent(), true);
- $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertGreaterThanOrEqual(1, \count($content));
$this->assertArrayHasKey('items', $content['_embedded']);
$this->assertGreaterThanOrEqual(1, $content['total']);
$this->assertSame(1, $content['page']);
$content = json_decode($this->client->getResponse()->getContent(), true);
- $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertGreaterThanOrEqual(1, \count($content));
$this->assertNotEmpty($content['_embedded']['items']);
$this->assertGreaterThanOrEqual(1, $content['total']);
$this->assertSame(1, $content['page']);
$content = json_decode($this->client->getResponse()->getContent(), true);
- $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertGreaterThanOrEqual(1, \count($content));
$this->assertNotEmpty($content['_embedded']['items']);
$this->assertGreaterThanOrEqual(1, $content['total']);
$this->assertSame(1, $content['page']);
$content = json_decode($this->client->getResponse()->getContent(), true);
- $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertGreaterThanOrEqual(1, \count($content));
$this->assertNotEmpty($content['_embedded']['items']);
$this->assertGreaterThanOrEqual(1, $content['total']);
$this->assertSame(1, $content['page']);
$content = json_decode($this->client->getResponse()->getContent(), true);
- $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertGreaterThanOrEqual(1, \count($content));
$this->assertNotEmpty($content['_embedded']['items']);
$this->assertGreaterThanOrEqual(1, $content['total']);
$this->assertSame(1, $content['page']);
$content = json_decode($this->client->getResponse()->getContent(), true);
- $this->assertGreaterThanOrEqual(1, count($content));
+ $this->assertGreaterThanOrEqual(1, \count($content));
$this->assertEmpty($content['_embedded']['items']);
$this->assertSame(0, $content['total']);
$this->assertSame(1, $content['page']);
$this->assertSame($entry->getId(), $content['id']);
$this->assertSame($entry->getUrl(), $content['url']);
$this->assertSame('New awesome title', $content['title']);
- $this->assertGreaterThanOrEqual(1, count($content['tags']), 'We force only one tag');
+ $this->assertGreaterThanOrEqual(1, \count($content['tags']), 'We force only one tag');
$this->assertSame(1, $content['user_id']);
$this->assertSame('de_AT', $content['language']);
$this->assertSame('http://preview.io/picture.jpg', $content['preview_picture']);
$this->assertSame($entry->getId(), $content['id']);
$this->assertSame($entry->getUrl(), $content['url']);
- $this->assertGreaterThanOrEqual(1, count($content['tags']), 'We force only one tag');
+ $this->assertGreaterThanOrEqual(1, \count($content['tags']), 'We force only one tag');
$this->assertEmpty($content['published_by'], 'Authors were not saved because of an array instead of a string');
$this->assertSame($previousContent, $content['content'], 'Ensure content has not moved');
$this->assertSame($previousLanguage, $content['language'], 'Ensure language has not moved');
$this->markTestSkipped('No content found in db.');
}
- $nbTags = count($entry->getTags());
+ $nbTags = \count($entry->getTags());
$newTags = 'tag1,tag2,tag3';
$content = json_decode($this->client->getResponse()->getContent(), true);
$this->assertArrayHasKey('tags', $content);
- $this->assertSame($nbTags + 3, count($content['tags']));
+ $this->assertSame($nbTags + 3, \count($content['tags']));
$entryDB = $this->client->getContainer()
->get('doctrine.orm.entity_manager')
}
// hydrate the tags relations
- $nbTags = count($entry->getTags());
+ $nbTags = \count($entry->getTags());
$tag = $entry->getTags()[0];
$this->client->request('DELETE', '/api/entries/' . $entry->getId() . '/tags/' . $tag->getId() . '.json');
$content = json_decode($this->client->getResponse()->getContent(), true);
$this->assertArrayHasKey('tags', $content);
- $this->assertSame($nbTags - 1, count($content['tags']));
+ $this->assertSame($nbTags - 1, \count($content['tags']));
}
public function testSaveIsArchivedAfterPost()
public function testPostWithMultipleAuthors()
{
- $url = 'http://www.liberation.fr/planete/2017/04/05/donald-trump-et-xi-jinping-tentative-de-flirt-en-floride_1560768';
+ $url = 'https://www.liberation.fr/planete/2017/04/05/donald-trump-et-xi-jinping-tentative-de-flirt-en-floride_1560768';
$this->logInAs('admin');
$client = $this->getClient();
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId($url, $this->getLoggedInUserId());
+ $this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $content);
$authors = $content->getPublishedBy();
$this->assertSame('2017-04-05 19:26:13', $content->getPublishedAt()->format('Y-m-d H:i:s'));
$this->assertSame('fr', $content->getLanguage());
$this->assertGreaterThan(1, $title = $crawler->filter('div[id=article] h1')->extract(['_text']));
$this->assertContains('My updated title hehe :)', $title[0]);
- $this->assertSame(1, count($stats = $crawler->filter('div[class=tools] ul[class=stats] li a[class=tool]')->extract(['_text'])));
+ $this->assertSame(1, \count($stats = $crawler->filter('div[class=tools] ul[class=stats] li a[class=tool]')->extract(['_text'])));
$this->assertNotContains('example.io', trim($stats[0]));
}
'http://www.hao123.com/shequ?__noscript__-=1',
'zh_CN',
],
- 'de_AT' => [
- 'https://buy.garmin.com/de-AT/AT/catalog/product/compareResult.ep?compareProduct=112885&compareProduct=36728',
- 'de_AT',
- ],
- 'ru_RU' => [
- 'http://netler.ru/ikt/windows-error-reporting.htm',
- 'ru_RU',
+ 'ru' => [
+ 'https://www.kp.ru/daily/26879.7/3921982/',
+ 'ru',
],
'pt_BR' => [
- 'http://precodoscombustiveis.com.br/postos/cidade/4121/pr/maringa',
+ 'https://politica.estadao.com.br/noticias/eleicoes,campanha-catatonica,70002491983',
'pt_BR',
],
'fucked_list_of_languages' => [
$this->assertGreaterThan(1, $csv);
// +1 for title line
- $this->assertSame(count($contentInDB) + 1, count($csv));
+ $this->assertSame(\count($contentInDB) + 1, \count($csv));
$this->assertSame('Title;URL;Content;Tags;"MIME Type";Language;"Creation date"', $csv[0]);
$this->assertContains($contentInDB[0]['title'], $csv[1]);
$this->assertContains($contentInDB[0]['url'], $csv[1]);
$content = new \SimpleXMLElement($client->getResponse()->getContent());
$this->assertGreaterThan(0, $content->count());
- $this->assertSame(count($contentInDB), $content->count());
+ $this->assertSame(\count($contentInDB), $content->count());
$this->assertNotEmpty('id', (string) $content->entry[0]->id);
$this->assertNotEmpty('title', (string) $content->entry[0]->title);
$this->assertNotEmpty('url', (string) $content->entry[0]->url);
$tags[$key] = $tag->getLabel();
}
- $this->assertGreaterThanOrEqual(2, count($tags));
+ $this->assertGreaterThanOrEqual(2, \count($tags));
$this->assertNotFalse(array_search('foo2', $tags, true), 'Tag foo2 is assigned to the entry');
$this->assertNotFalse(array_search('bar2', $tags, true), 'Tag bar2 is assigned to the entry');
}
$this->assertSame('1.1.1.1', $entry->getDomainName());
}
+ public function testWebsiteWithValidUTF8Title_doNothing()
+ {
+ // You can use https://www.online-toolz.com/tools/text-hex-convertor.php to convert UTF-8 text <=> hex
+ // See http://graphemica.com for more info about the characters
+ // '😻ℤz' (U+1F63B or F09F98BB; U+2124 or E284A4; U+007A or 7A) in hexadecimal and UTF-8
+ $actualTitle = $this->hexToStr('F09F98BB' . 'E284A4' . '7A');
+
+ $tagger = $this->getTaggerMock();
+ $tagger->expects($this->once())
+ ->method('tag');
+
+ $graby = $this->getMockBuilder('Graby\Graby')
+ ->setMethods(['fetchContent'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $graby->expects($this->any())
+ ->method('fetchContent')
+ ->willReturn([
+ 'html' => false,
+ 'title' => $actualTitle,
+ 'url' => '',
+ 'content_type' => 'text/html',
+ 'language' => '',
+ ]);
+
+ $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
+ $entry = new Entry(new User());
+ $proxy->updateEntry($entry, 'http://0.0.0.0');
+
+ // '😻ℤz' (U+1F63B or F09F98BB; U+2124 or E284A4; U+007A or 7A) in hexadecimal and UTF-8
+ $expectedTitle = 'F09F98BB' . 'E284A4' . '7A';
+ $this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
+ }
+
+ public function testWebsiteWithInvalidUTF8Title_removeInvalidCharacter()
+ {
+ // See http://graphemica.com for more info about the characters
+ // 'a€b' (61;80;62) in hexadecimal and WINDOWS-1252 - but 80 is a invalid UTF-8 character.
+ // The correct UTF-8 € character (U+20AC) is E282AC
+ $actualTitle = $this->hexToStr('61' . '80' . '62');
+
+ $tagger = $this->getTaggerMock();
+ $tagger->expects($this->once())
+ ->method('tag');
+
+ $graby = $this->getMockBuilder('Graby\Graby')
+ ->setMethods(['fetchContent'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $graby->expects($this->any())
+ ->method('fetchContent')
+ ->willReturn([
+ 'html' => false,
+ 'title' => $actualTitle,
+ 'url' => '',
+ 'content_type' => 'text/html',
+ 'language' => '',
+ ]);
+
+ $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
+ $entry = new Entry(new User());
+ $proxy->updateEntry($entry, 'http://0.0.0.0');
+
+ // 'ab' (61;62) because all invalid UTF-8 character (like 80) are removed
+ $expectedTitle = '61' . '62';
+ $this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
+ }
+
+ public function testPdfWithUTF16BETitle_convertToUTF8()
+ {
+ // See http://graphemica.com for more info about the characters
+ // '😻' (U+1F63B;D83DDE3B) in hexadecimal and as UTF16BE
+ $actualTitle = $this->hexToStr('D83DDE3B');
+
+ $tagger = $this->getTaggerMock();
+ $tagger->expects($this->once())
+ ->method('tag');
+
+ $graby = $this->getMockBuilder('Graby\Graby')
+ ->setMethods(['fetchContent'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $graby->expects($this->any())
+ ->method('fetchContent')
+ ->willReturn([
+ 'html' => false,
+ 'title' => $actualTitle,
+ 'url' => '',
+ 'content_type' => 'application/pdf',
+ 'language' => '',
+ ]);
+
+ $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
+ $entry = new Entry(new User());
+ $proxy->updateEntry($entry, 'http://0.0.0.0');
+
+ // '😻' (U+1F63B or F09F98BB) in hexadecimal and UTF-8
+ $expectedTitle = 'F09F98BB';
+ $this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
+ }
+
+ public function testPdfWithUTF8Title_doNothing()
+ {
+ // See http://graphemica.com for more info about the characters
+ // '😻' (U+1F63B;D83DDE3B) in hexadecimal and as UTF8
+ $actualTitle = $this->hexToStr('F09F98BB');
+
+ $tagger = $this->getTaggerMock();
+ $tagger->expects($this->once())
+ ->method('tag');
+
+ $graby = $this->getMockBuilder('Graby\Graby')
+ ->setMethods(['fetchContent'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $graby->expects($this->any())
+ ->method('fetchContent')
+ ->willReturn([
+ 'html' => false,
+ 'title' => $actualTitle,
+ 'url' => '',
+ 'content_type' => 'application/pdf',
+ 'language' => '',
+ ]);
+
+ $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
+ $entry = new Entry(new User());
+ $proxy->updateEntry($entry, 'http://0.0.0.0');
+
+ // '😻' (U+1F63B or F09F98BB) in hexadecimal and UTF-8
+ $expectedTitle = 'F09F98BB';
+ $this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
+ }
+
+ public function testPdfWithWINDOWS1252Title_convertToUTF8()
+ {
+ // See http://graphemica.com for more info about the characters
+ // '€' (80) in hexadecimal and WINDOWS-1252
+ $actualTitle = $this->hexToStr('80');
+
+ $tagger = $this->getTaggerMock();
+ $tagger->expects($this->once())
+ ->method('tag');
+
+ $graby = $this->getMockBuilder('Graby\Graby')
+ ->setMethods(['fetchContent'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $graby->expects($this->any())
+ ->method('fetchContent')
+ ->willReturn([
+ 'html' => false,
+ 'title' => $actualTitle,
+ 'url' => '',
+ 'content_type' => 'application/pdf',
+ 'language' => '',
+ ]);
+
+ $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
+ $entry = new Entry(new User());
+ $proxy->updateEntry($entry, 'http://0.0.0.0');
+
+ // '€' (U+20AC or E282AC) in hexadecimal and UTF-8
+ $expectedTitle = 'E282AC';
+ $this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
+ }
+
+ public function testPdfWithInvalidCharacterInTitle_removeInvalidCharacter()
+ {
+ // See http://graphemica.com for more info about the characters
+ // '😻ℤ�z' (U+1F63B or F09F98BB; U+2124 or E284A4; invalid character 81; U+007A or 7A) in hexadecimal and UTF-8
+ // 0x81 is not a valid character for UTF16, UTF8 and WINDOWS-1252
+ $actualTitle = $this->hexToStr('F09F98BB' . 'E284A4' . '81' . '7A');
+
+ $tagger = $this->getTaggerMock();
+ $tagger->expects($this->once())
+ ->method('tag');
+
+ $graby = $this->getMockBuilder('Graby\Graby')
+ ->setMethods(['fetchContent'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $graby->expects($this->any())
+ ->method('fetchContent')
+ ->willReturn([
+ 'html' => false,
+ 'title' => $actualTitle,
+ 'url' => '',
+ 'content_type' => 'application/pdf',
+ 'language' => '',
+ ]);
+
+ $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
+ $entry = new Entry(new User());
+ $proxy->updateEntry($entry, 'http://0.0.0.0');
+
+ // '😻ℤz' (U+1F63B or F09F98BB; U+2124 or E284A4; U+007A or 7A) in hexadecimal and UTF-8
+ // the 0x81 (represented by �) is invalid for UTF16, UTF8 and WINDOWS-1252 and is removed
+ $expectedTitle = 'F09F98BB' . 'E284A4' . '7A';
+ $this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
+ }
+
+ /**
+ * https://stackoverflow.com/a/18506801.
+ *
+ * @param $string
+ *
+ * @return string
+ */
+ private function strToHex($string)
+ {
+ $hex = '';
+ for ($i = 0; $i < \strlen($string); ++$i) {
+ $ord = \ord($string[$i]);
+ $hexCode = dechex($ord);
+ $hex .= substr('0' . $hexCode, -2);
+ }
+
+ return strtoupper($hex);
+ }
+
+ /**
+ * https://stackoverflow.com/a/18506801.
+ *
+ * @param $hex
+ *
+ * @return string
+ */
+ private function hexToStr($hex)
+ {
+ $string = '';
+ for ($i = 0; $i < \strlen($hex) - 1; $i += 2) {
+ $string .= \chr(hexdec($hex[$i] . $hex[$i + 1]));
+ }
+
+ return $string;
+ }
+
private function getTaggerMock()
{
return $this->getMockBuilder(RuleBasedTagger::class)
$this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $content);
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://www.usinenouvelle.com is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://www.usinenouvelle.com is ok');
- $this->assertSame(1, count($content->getTags()));
+ $this->assertSame(1, \count($content->getTags()));
$createdAt = $content->getCreatedAt();
$this->assertSame('2011', $createdAt->format('Y'));
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for http://lexpansion.lexpress.fr is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://lexpansion.lexpress.fr is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://lexpansion.lexpress.fr is ok');
- $this->assertSame(3, count($content->getTags()));
+ $this->assertSame(3, \count($content->getTags()));
$content = $client->getContainer()
->get('doctrine.orm.entity_manager')
->get('doctrine.orm.entity_manager')
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId(
- 'http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551',
+ 'https://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551',
$this->getLoggedInUserId()
);
- $this->assertNotEmpty($content->getMimetype(), 'Mimetype for http://www.liberation.fr is ok');
- $this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://www.liberation.fr is ok');
- $this->assertNotEmpty($content->getLanguage(), 'Language for http://www.liberation.fr is ok');
+ $this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $content);
+
+ $this->assertNotEmpty($content->getMimetype(), 'Mimetype for https://www.liberation.fr is ok');
+ $this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for https://www.liberation.fr is ok');
+ $this->assertNotEmpty($content->getLanguage(), 'Language for https://www.liberation.fr is ok');
$this->assertContains('foot', $content->getTags(), 'It includes the "foot" tag');
- $this->assertSame(1, count($content->getTags()));
+ $this->assertSame(1, \count($content->getTags()));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
$content = $client->getContainer()
$this->assertContains('foot', $content->getTags());
$this->assertContains('test_tag', $content->getTags());
- $this->assertSame(2, count($content->getTags()));
+ $this->assertSame(2, \count($content->getTags()));
}
public function testImportInstapaperWithFileAndMarkAllAsRead()
$this->assertContains('foot', $tags, 'It includes the "foot" tag');
$this->assertContains('varnish', $tags, 'It includes the "varnish" tag');
$this->assertContains('php', $tags, 'It includes the "php" tag');
- $this->assertSame(3, count($tags));
+ $this->assertSame(3, \count($tags));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
$this->assertSame('2016-10-26', $content->getCreatedAt()->format('Y-m-d'));
$tags = $content->getTags();
$this->assertContains('foot', $tags, 'It includes the "foot" tag');
- $this->assertSame(1, count($tags));
+ $this->assertSame(1, \count($tags));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
$this->assertSame('2016-09-08', $content->getCreatedAt()->format('Y-m-d'));
$tags = $content->getTags();
$this->assertContains('foot', $tags, 'It includes the "foot" tag');
$this->assertContains('framabag', $tags, 'It includes the "framabag" tag');
- $this->assertSame(2, count($tags));
+ $this->assertSame(2, \count($tags));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
}
->get('doctrine.orm.entity_manager')
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId(
- 'http://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867',
+ 'https://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867',
$this->getLoggedInUserId()
);
$this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $content);
// empty because it wasn't re-imported
- $this->assertEmpty($content->getMimetype(), 'Mimetype for http://www.liberation.fr is empty');
- $this->assertEmpty($content->getPreviewPicture(), 'Preview picture for http://www.liberation.fr is empty');
- $this->assertEmpty($content->getLanguage(), 'Language for http://www.liberation.fr is empty');
+ $this->assertEmpty($content->getMimetype(), 'Mimetype for https://www.liberation.fr is empty');
+ $this->assertEmpty($content->getPreviewPicture(), 'Preview picture for https://www.liberation.fr is empty');
+ $this->assertEmpty($content->getLanguage(), 'Language for https://www.liberation.fr is empty');
$tags = $content->getTags();
$this->assertContains('foot', $tags, 'It includes the "foot" tag');
- $this->assertSame(1, count($tags));
+ $this->assertSame(1, \count($tags));
$content = $client->getContainer()
->get('doctrine.orm.entity_manager')
$this->assertContains('foot', $tags, 'It includes the "foot" tag');
$this->assertContains('mediapart', $tags, 'It includes the "mediapart" tag');
$this->assertContains('blog', $tags, 'It includes the "blog" tag');
- $this->assertSame(3, count($tags));
+ $this->assertSame(3, \count($tags));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());
$this->assertSame('2016-09-08', $content->getCreatedAt()->format('Y-m-d'));
URL,Title,Selection,Folder
-http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551,Baumettes : un tour en cellule,,Unread
+https://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551,Baumettes : un tour en cellule,,Unread
https://redditblog.com/2016/09/20/amp-and-reactredux/,AMP and React+Redux: Why Not?,,Archive
https://medium.com/@the_minh/why-foursquare-swarm-is-still-my-favourite-social-network-e38228493e6c,Why Foursquare / Swarm is still my favourite social network,,Starred
https://www.20minutes.fr/high-tech/2077615-20170531-quoi-exactement-tweet-covfefe-donald-trump-persiste-signe,"Dis donc Donald Trump, c'est quoi exactement «covfefe»?",,test_tag
{
"id": 22,
"title": "Réfugiés: l'UE va créer 100 000 places d'accueil dans les Balkans",
- "url": "http://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867",
+ "url": "https://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867",
"is_archived": false,
"created_at": "2016-09-08T11:55:58+0200",
"updated_at": "2016-09-08T11:57:16+0200",
{
public function count()
{
- return count($this->messages);
+ return \count($this->messages);
}
public function getMessages()
{
/* mandatory requirements follow */
- $installedPhpVersion = phpversion();
+ $installedPhpVersion = PHP_VERSION;
$requiredPhpVersion = $this->getPhpRequiredVersion();
$this->addRecommendation(
}
if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) {
- $timezones = array();
- foreach (DateTimeZone::listAbbreviations() as $abbreviations) {
- foreach ($abbreviations as $abbreviation) {
- $timezones[$abbreviation['timezone_id']] = true;
- }
- }
-
$this->addRequirement(
- isset($timezones[@date_default_timezone_get()]),
+ in_array(@date_default_timezone_get(), DateTimeZone::listIdentifiers(), true),
sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()),
'Your default timezone is not supported by PHP. Check for typos in your <strong>php.ini</strong> file and have a look at the list of deprecated timezones at <a href="http://php.net/manual/en/timezones.others.php">http://php.net/manual/en/timezones.others.php</a>.'
);
'Install and/or enable a <strong>PHP accelerator</strong> (highly recommended).'
);
- if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+ if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) {
$this->addRecommendation(
$this->getRealpathCacheSize() >= 5 * 1024 * 1024,
'realpath_cache_size should be at least 5M in php.ini',
hoek "2.x.x"
sntp "1.x.x"
+highlight.js@^9.12.0:
+ version "9.12.0"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
+
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"