Skip to content

Commit e6e95e7

Browse files
committed
Merge pull request phpList#20 from michield/stable
major update
2 parents 86d93ff + 0bb1fac commit e6e95e7

27 files changed

+1078
-4596
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
# whitelist
33
language: php
44
php:
5-
- 7.0
65
- 5.6
76
- 5.5
87
- 5.4
@@ -21,6 +20,7 @@ before_script:
2120
- composer self-update
2221
- composer install --prefer-dist
2322
- sudo cp -f tests/travis-ci/behat.yml behat.yml
23+
- sudo cp -f tests/travis-ci/phpunit.xml tests/phpunit/
2424

2525
# Set MySQL configuration and create the database.
2626
- mysql -e 'SET GLOBAL wait_timeout = 5400;'

README.md

+2-6
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ Log in to /admin and the collapsed "Plugins" menu should have two links added: "
4848

4949
Click on the item "RESTAPI" item for more information!
5050

51-
###4. Test
52-
Click on "restapi test" to test your installation of the API plugin!
53-
5451
##Access
5552
Autentication required as admin in phpList.
5653

@@ -65,11 +62,10 @@ First login to phpList with *POST* method and body parameters: "login" and "pass
6562

6663

6764
##Client
68-
To try the RESTAPI, please use a client like CocaRestClient or eqvivalent!
6965

70-
There is an example class in restapi-test/phplist_restapi_helper.php if you like to try it in PHP.
66+
Some examples and a client class to access the API can be found at
7167

72-
For examples check commands in restapi-test/main.php
68+
https://github.com/michield/phplist-restapi-client
7369

7470
##Standard reponse
7571
All responses is returned in json and encoded to UTF-8.

plugins/restapi.php

+66-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@
77
*
88
* version history:
99
*
10+
* v 3 2015-11-19
11+
* - updated some calls
12+
* - added more security checks
13+
* - added phpunit tests
14+
* - removed obsolete fields
15+
* - added limit to subscriber retrieval
16+
* - added limit to campaign retrieval
17+
* - renamed messages to campaigns
18+
* - renamed users to subscribers
19+
*
1020
* v 2 * phpList Api Team https://github.com/orgs/phpList/teams/api
1121
* - renamed plugin repository to phplist-plugin-restapi
1222
* - https://github.com/phpList/phplist-plugin-restapi
@@ -20,20 +30,72 @@ class restapi extends phplistPlugin
2030
{
2131
public $name = 'RESTAPI';
2232
public $description = 'Implements a REST API interface to phpList';
33+
public $version = 3;
34+
public $documentationUrl = 'https://resources.phplist.com/plugin/restapi';
2335
public $topMenuLinks = array(
2436
'main' => array('category' => 'system'),
2537
);
2638

27-
public function restapi()
39+
public $DBstruct = array(
40+
'request_log' => array(
41+
'id' => array('integer not null primary key auto_increment', 'ID'),
42+
'url' => array('text not null', ''),
43+
'cmd' => array('varchar(150) not null',''),
44+
'ip' => array('varchar(15) not null',''),
45+
'request' => array('text not null', ''),
46+
'date' => array('timestamp not null', ''),
47+
'index_1' => array('dateidx (date)',''),
48+
'index_2' => array('cmdidx (cmd)',''),
49+
'index_3' => array('ipidx (ip)',''),
50+
),
51+
);
52+
53+
public $settings = array(
54+
'restapi_limit' => array(
55+
'description' => 'Maximum number of RESTAPI requests per minute',
56+
'type' => 'integer',
57+
'value' => 60,
58+
'allowempty' => false,
59+
'min' => 1,
60+
'max' => 1200,
61+
'category' => 'Security',
62+
),
63+
'restapi_enforcessl' => array(
64+
'description' => 'Require SSL on Rest API calls',
65+
'type' => 'boolean',
66+
'allowempty' => true,
67+
'value' => false,
68+
'category' => 'Security',
69+
),
70+
'restapi_ipaddress' => array(
71+
'description' => 'IP Address that is allowed to access the API',
72+
'type' => 'text',
73+
'allowempty' => true,
74+
'value' => '',
75+
'category' => 'Security',
76+
),
77+
'restapi_usesecret' => array(
78+
'description' => 'Require the secret code for Rest API calls',
79+
'type' => 'boolean',
80+
'allowempty' => true,
81+
'value' => false,
82+
'category' => 'Security',
83+
),
84+
);
85+
public function __construct()
2886
{
29-
parent::phplistplugin();
30-
$this->coderoot = dirname(__FILE__).'/restapi/';
87+
$this->coderoot = dirname(__FILE__).'/'.__CLASS__.'/';
88+
parent::__construct();
89+
if (!Sql_Table_exists($GLOBALS['table_prefix'].'restapi_request_log')) {
90+
saveConfig(md5('plugin-restapi-initialised'), false, 0);
91+
$this->initialise();
92+
}
3193
}
3294

3395
public function adminmenu()
3496
{
3597
return array(
36-
'main' => 'RESTAPI',
98+
'main' => 'RESTAPI Main',
3799
);
38100
}
39101
}

plugins/restapi/call.php

+47-30
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,69 @@
44

55
defined('PHPLISTINIT') || die;
66

7-
//No HTML-output, please!
8-
ob_end_clean();
97

108
//Getting phpList globals for this plugin
119
$plugin = $GLOBALS['plugins'][$_GET['pi']];
1210

13-
include 'includes/response.php';
14-
include 'includes/pdo.php';
15-
16-
include 'includes/common.php';
17-
18-
include 'includes/actions.php';
19-
include 'includes/lists.php';
20-
include 'includes/subscribers.php';
21-
include 'includes/templates.php';
22-
include 'includes/messages.php';
23-
24-
include 'doc/doc.php';
25-
26-
if (function_exists('api_request_log')) {
27-
api_request_log();
28-
}
29-
30-
//Check if this is called outside phpList auth, this should never occur!
31-
if (empty($plugin->coderoot)) {
32-
Response::outputErrorMessage('Not authorized! Please login with [login] and [password] as admin first!');
33-
}
34-
11+
include_once 'includes/response.php';
12+
include_once 'includes/pdo.php';
13+
include_once 'includes/common.php';
14+
include_once 'includes/actions.php';
15+
include_once 'includes/lists.php';
16+
include_once 'includes/subscribers.php';
17+
include_once 'includes/templates.php';
18+
include_once 'includes/campaigns.php';
3519
//If other than POST then assume documentation report
3620
if (strcmp($_SERVER['REQUEST_METHOD'], 'POST')) {
37-
$doc = new \phpListRestapiDoc();
21+
include_once 'doc/doc.php';
22+
$doc = new phpListRestapiDoc();
3823
$doc->addClass('Actions');
3924
$doc->addClass('Lists');
4025
$doc->addClass('Subscribers');
4126
$doc->addClass('Templates');
42-
$doc->addClass('Messages');
43-
$doc->output();
27+
$doc->addClass('Campaigns');
28+
print $doc->output();
29+
return;
4430
}
31+
ob_end_clean();
4532

46-
//Check if command is empty!
4733
$cmd = $_REQUEST['cmd'];
4834
$cmd = preg_replace('/\W/', '', $cmd);
4935
if (empty($cmd)) {
5036
Response::outputMessage('OK! For action, please provide Post Param Key [cmd] !');
5137
}
5238

39+
if (function_exists('api_request_log')) {
40+
api_request_log();
41+
}
42+
43+
if (empty($plugin->coderoot)) {
44+
Response::outputErrorMessage('Not authorized! Please login with [login] and [password] as admin first!');
45+
}
46+
47+
if ($cmd != 'login') {
48+
Common::logRequest($cmd);
49+
Common::enforceRequestLimit(getConfig('restapi_limit'));
50+
}
51+
$ipAddress = getConfig('restapi_ipaddress');
52+
if (!empty($ipAddress) && ($GLOBALS['remoteAddr'] != $ipAddress)) {
53+
$response->outputErrorMessage('Incorrect ip address for request. Check your settings.');
54+
die(0);
55+
}
56+
$requireSecret = getConfig('restapi_usesecret');
57+
if ($requireSecret) {
58+
$secret = getConfig('remote_processing_secret');
59+
if (empty($_REQUEST['secret']) || $_REQUEST['secret'] != $secret) {
60+
$response->outputErrorMessage('Incorrect processing secret. Check your settings.');
61+
die(0);
62+
}
63+
}
64+
$enforceSSL = getConfig('restapi_enforcessl');
65+
if ($enforceSSL && empty($_SERVER['HTTPS'])) {
66+
$response->outputErrorMessage('Invalid API request. Request is not using SSL, which is enforced by the plugin settings.');
67+
die(0);
68+
}
69+
5370
//Now bind the commands with static functions
5471
if (is_callable(array('phpListRestapi\Lists', $cmd))) {
5572
Lists::$cmd();
@@ -63,8 +80,8 @@
6380
if (is_callable(array('phpListRestapi\Templates', $cmd))) {
6481
Templates::$cmd();
6582
}
66-
if (is_callable(array('phpListRestapi\Messages', $cmd))) {
67-
Messages::$cmd();
83+
if (is_callable(array('phpListRestapi\Campaigns', $cmd))) {
84+
Campaigns::$cmd();
6885
}
6986

7087
//If no command found, return error message!

plugins/restapi/doc/doc.php

+44-54
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
namespace phpListRestapi;
23

34
class phpListRestapiDoc
45
{
@@ -15,97 +16,86 @@ public function addClass($classname)
1516

1617
public function output()
1718
{
18-
$this->header();
19+
$output = $this->header();
1920

2021
foreach ($this->classes as $class) {
2122
$reflect = new \ReflectionClass($class);
2223
$methods = $reflect->getMethods();
2324
foreach ($methods as $method) {
24-
echo '<section>';
25-
echo '<div class="page-header">';
26-
echo '<h2>'.$method->name.'</h2>';
27-
echo '</div>';
28-
echo '<div class="row">';
29-
echo '<div class="span12">';
30-
31-
$comment = $method->getDocComment();
32-
33-
$comment = str_replace('/**', '', $comment);
34-
$comment = str_replace('*/', '', $comment);
35-
$comment = str_replace('[*', '<span class="label label-warning">', $comment);
36-
$comment = str_replace('[', '<span class="label label-success">', $comment);
37-
$comment = str_replace(']', '</span>', $comment);
38-
$comment = str_replace('{', '<span class="badge">', $comment);
39-
$comment = str_replace('}', '</span>', $comment);
40-
$comment = str_replace('*', '', $comment);
41-
//$comment = str_replace( '<br><br>', '', $comment );
42-
43-
echo trim($comment);
44-
45-
echo '</div>';
46-
echo '</div>';
47-
echo '<br/>';
48-
echo '<section>';
25+
if (Common::method_allowed($reflect->getShortName(),$method->name)) {
26+
$output .= '<section>';
27+
$output .= '<div class="page-header">';
28+
# $output .= '<h2>'.$reflect->getShortName().'</h2>';
29+
$output .= '<h2>'.$method->name.'</h2>';
30+
$output .= '</div>';
31+
$output .= '<div class="row">';
32+
$output .= '<div class="span12">';
33+
34+
$comment = $method->getDocComment();
35+
36+
$comment = str_replace('/**', '', $comment);
37+
$comment = str_replace('*/', '', $comment);
38+
$comment = str_replace('[*', '<span class="restapi-param param-required">', $comment);
39+
$comment = str_replace('[', '<span class="restapi-param param-optional">', $comment);
40+
$comment = str_replace(']', '</span>', $comment);
41+
$comment = str_replace('{', '<span class="restapi-datatype">', $comment);
42+
$comment = str_replace('}', '</span>', $comment);
43+
$comment = str_replace('*', '', $comment);
44+
//$comment = str_replace( '<br><br>', '', $comment );
45+
46+
$output .= trim($comment);
47+
48+
$output .= '</div>';
49+
$output .= '</div>';
50+
$output .= '<br/>';
51+
$output .= '</section>';
52+
}
4953
}
5054
}
5155

52-
$this->footer();
56+
$output .= $this->footer();
5357

54-
exit;
58+
return $output;
5559
}
5660

5761
public function header()
5862
{
59-
?>
60-
61-
<!DOCTYPE html>
62-
<html>
63-
<head>
64-
<title>API Plugin to phpList</title>
65-
<!-- Bootstrap -->
66-
<link href="http://netdna.bootstrapcdn.com/bootswatch/2.1.1/cerulean/bootstrap.min.css" rel="stylesheet" media="screen">
67-
</head>
68-
<body>
69-
<div class="container">
70-
71-
<p>&nbsp;</p>
63+
return '
7264
7365
<header class="jumbotron subhead" id="overview">
7466
<div class="row">
75-
<div class="span6">
67+
<div class="xspan6">
7668
<h1>API Plugin to phpList</h1>
77-
<p class="lead">Documentation generated <?php echo date('Y-m-d H:i:s');
78-
?></p>
69+
<p class="lead">Documentation generated '. date('Y-m-d H:i:s').'
70+
</p>
7971
</div>
8072
</div>
8173
</header>
8274
<div class="row">
83-
<div class="span12">
75+
<div class="xspan12">
8476
<div class="well">
8577
The following methods is called by Body Param [cmd] to the plugin URL via request method POST.
8678
<p>
87-
<span class="label label-warning">Required body parameter</span><br/>
88-
<span class="label label-success">Optional body parameter</span><br/>
89-
<span class="badge">Datatype</span><br/>
79+
<span class="restapi-param param-required">Required body parameter</span><br/>
80+
<span class="restapi-param param-optional">Optional body parameter</span><br/>
81+
<span class="restapi-datatype">Datatype</span><br/>
9082
</p>
9183
</div>
9284
</div>
9385
</div>
94-
<?php
86+
';
9587

9688
}
9789

9890
public function footer()
9991
{
100-
?>
92+
return '
10193
<footer id="footer">
10294
<p class="pull-right"><a href="#">Back to top</a></p>
10395
</footer>
104-
</div>
105-
</body>
106-
</html>
10796
108-
<?php
97+
98+
';
10999

110100
}
111101
}

0 commit comments

Comments
 (0)