aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag/CoreBundle/Helper/FileCookieJar.php
blob: 9a63e9493259b45f8c7b4bc0771661c713936948 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?php

namespace Wallabag\CoreBundle\Helper;

use GuzzleHttp\Cookie\FileCookieJar as BaseFileCookieJar;
use GuzzleHttp\Cookie\SetCookie;
use GuzzleHttp\Utils;
use Psr\Log\LoggerInterface;

/**
 * Overidden Cookie behavior to:
 *     - fix multiple concurrent writes (see https://github.com/guzzle/guzzle/pull/1884)
 *     - ignore error when the cookie file is malformatted (resulting in clearing it).
 */
class FileCookieJar extends BaseFileCookieJar
{
    private $logger;

    /**
     * @param LoggerInterface $logger     Only used to log info when something goes wrong
     * @param string          $cookieFile File to store the cookie data
     */
    public function __construct(LoggerInterface $logger, $cookieFile)
    {
        parent::__construct($cookieFile);

        $this->logger = $logger;
    }

    /**
     * Saves the cookies to a file.
     *
     * @param string $filename File to save
     *
     * @throws \RuntimeException if the file cannot be found or created
     */
    public function save($filename)
    {
        $json = [];
        foreach ($this as $cookie) {
            if ($cookie->getExpires() && !$cookie->getDiscard()) {
                $json[] = $cookie->toArray();
            }
        }

        if (false === file_put_contents($filename, json_encode($json), LOCK_EX)) {
            // @codeCoverageIgnoreStart
            throw new \RuntimeException("Unable to save file {$filename}");
            // @codeCoverageIgnoreEnd
        }
    }

    /**
     * Load cookies from a JSON formatted file.
     *
     * Old cookies are kept unless overwritten by newly loaded ones.
     *
     * @param string $filename cookie file to load
     *
     * @throws \RuntimeException if the file cannot be loaded
     */
    public function load($filename)
    {
        $json = file_get_contents($filename);
        if (false === $json) {
            // @codeCoverageIgnoreStart
            throw new \RuntimeException("Unable to load file {$filename}");
            // @codeCoverageIgnoreEnd
        }

        try {
            $data = Utils::jsonDecode($json, true);
        } catch (\InvalidArgumentException $e) {
            $this->logger->error('JSON inside the cookie is broken', [
                'json' => $json,
                'error_msg' => $e->getMessage(),
            ]);

            // cookie file is invalid, just ignore the exception and it'll reset the whole cookie file
            $data = '';
        }

        if (\is_array($data)) {
            foreach (Utils::jsonDecode($json, true) as $cookie) {
                $this->setCookie(new SetCookie($cookie));
            }
        } elseif (\strlen($data)) {
            throw new \RuntimeException("Invalid cookie file: {$filename}");
        }
    }
}