File: API.php

package info (click to toggle)
matomo 5.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 95,068 kB
  • sloc: php: 289,425; xml: 127,249; javascript: 112,130; python: 202; sh: 178; makefile: 20; sql: 10
file content (158 lines) | stat: -rw-r--r-- 4,393 bytes parent folder | download
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */

namespace Piwik\Plugin;

use Piwik\Container\StaticContainer;
use Piwik\Piwik;
use Piwik\Plugins\Login\PasswordVerifier;
use Piwik\Log\LoggerInterface;
use Exception;

/**
 * The base class of all API singletons.
 *
 * Plugins that want to expose functionality through the Reporting API should create a class
 * that extends this one. Every public method in that class that is not annotated with **@ignore**
 * will be callable through Matomo's Web API.
 *
 * _Note: If your plugin calculates and stores reports, they should be made available through the API._
 *
 * ### Examples
 *
 * **Defining an API for a plugin**
 *
 *     class API extends \Piwik\Plugin\API
 *     {
 *         public function myMethod($idSite, $period, $date, $segment = false)
 *         {
 *             $dataTable = // ... get some data ...
 *             return $dataTable;
 *         }
 *     }
 *
 * **Linking to an API method**
 *
 *     <a href="?module=API&method=MyPlugin.myMethod&idSite=1&period=day&date=2013-10-23">Link</a>
 *
 * @api
 */
abstract class API
{
    private static $instances;

    /** @var bool */
    protected $autoSanitizeInputParams = true;

    /**
     * Returns the singleton instance for the derived class. If the singleton instance
     * has not been created, this method will create it.
     *
     * @return static
     */
    public static function getInstance()
    {
        $class = get_called_class();

        if (!isset(self::$instances[$class])) {
            $container = StaticContainer::getContainer();

            $refl = new \ReflectionClass($class);

            if (!$refl->getConstructor() || $refl->getConstructor()->isPublic()) {
                self::$instances[$class] = $container->get($class);
            } else {
                /** @var LoggerInterface $logger */
                $logger = $container->get(LoggerInterface::class);

                // BC with API defining a protected constructor
                $logger->notice('The API class {class} defines a protected constructor which is deprecated, make the constructor public instead', ['class' => $class]);
                self::$instances[$class] = new $class();
            }
        }

        return self::$instances[$class];
    }

    /**
     * Used in tests only
     * @ignore
     * @internal
     */
    public static function unsetInstance()
    {
        $class = get_called_class();
        unset(self::$instances[$class]);
    }

    /**
     * Used in tests only
     * @ignore
     * @internal
     */
    public static function unsetAllInstances()
    {
        self::$instances = [];
    }

    /**
     * Sets the singleton instance. For testing purposes.
     * @ignore
     * @internal
     */
    public static function setSingletonInstance($instance)
    {
        $class = get_called_class();
        self::$instances[$class] = $instance;
    }

    /**
     * Verifies if the given password matches the current users password
     *
     * @param $passwordConfirmation
     * @throws Exception
     */
    protected function confirmCurrentUserPassword(
        #[\SensitiveParameter]
        $passwordConfirmation
    ) {
        $loginCurrentUser = Piwik::getCurrentUserLogin();

        if (!Piwik::doesUserRequirePasswordConfirmation($loginCurrentUser)) {
            return; // password confirmation disabled for user
        }

        if (empty($passwordConfirmation)) {
            throw new Exception(Piwik::translate('UsersManager_ConfirmWithReAuthentication'));
        }

        try {
            if (
                !StaticContainer::get(PasswordVerifier::class)->isPasswordCorrect(
                    $loginCurrentUser,
                    $passwordConfirmation
                )
            ) {
                throw new Exception(Piwik::translate('UsersManager_CurrentPasswordNotCorrect'));
            }
        } catch (Exception $e) {
            // in case of any error (e.g. the provided password is too weak)
            throw new Exception(Piwik::translate('UsersManager_CurrentPasswordNotCorrect'));
        }
    }

    /**
     * @return bool
     * @internal
     */
    public function usesAutoSanitizeInputParams()
    {
        return $this->autoSanitizeInputParams;
    }
}