1<?php
2/**
3 * AutoTweet 2 plugin
4 * Post the information of changes to Twitter
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     HokkaidoPerson <dosankomali@yahoo.co.jp>
8 */
9
10if(!defined('DOKU_INC')) die();
11
12
13class action_plugin_autotweet2 extends DokuWiki_Action_Plugin {
14
15    public function register(Doku_Event_Handler $controller) {
16        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'tweet', array());
17    }
18
19
20    //Reference: https://syncer.jp/Web/API/Twitter/REST_API/
21
22    public function tweet(Doku_Event $event, $param) {
23
24        // Load configurations and set up
25        $api_key = $this->getConf('apiKey');
26        $api_secret = $this->getConf('apiSecret');
27        $access_token = $this->getConf('accessToken');
28        $access_token_secret = $this->getConf('accessTokenSecret');
29        $request_url = 'https://api.twitter.com/1.1/statuses/update.json' ;
30        $request_method = 'POST' ;
31
32        // If keys and secrets are empty, the function will not run
33        if ($api_key == '' or $api_secret == '' or $access_token == '' or $access_token_secret == '') return;
34
35        // Check the blacklist
36        $blacklist = '|' . $this->getConf('blacklist') . '|';
37        $savingid = $event->data['id'];
38        if (strpos($blacklist, '|' . $savingid . '|') !== FALSE) return;
39
40
41        // Check the type of editing and the conf "subjectOfTweet"
42        $subject = $this->getConf('subjectOfTweet');
43
44        switch ($event->data['changeType']) {
45        case DOKU_CHANGE_TYPE_EDIT      : if (strpos($subject, 'edit') === FALSE) return; else $edittype = $this->getLang('edit');
46            break;
47        case DOKU_CHANGE_TYPE_REVERT    : if (strpos($subject, 'revert') === FALSE) return; else $edittype = $this->getLang('revert');
48            break;
49        case DOKU_CHANGE_TYPE_CREATE    : if (strpos($subject, 'create') === FALSE) return; else $edittype = $this->getLang('create');
50            break;
51        case DOKU_CHANGE_TYPE_DELETE    : if (strpos($subject, 'delete') === FALSE) return; else $edittype = $this->getLang('delete');
52            break;
53        case DOKU_CHANGE_TYPE_MINOR_EDIT: if (strpos($subject, 'minor') === FALSE) return; else $edittype = $this->getLang('minor');
54            break;
55        default:
56            return;
57        }
58
59        // Construct the message
60        $message = $this->getConf('template');
61        $message = str_replace('###WIKITITLE###', $conf['title'], $message);
62        $message = str_replace('###PAGETITLE###', tpl_pagetitle($savingid, 1), $message);
63        $message = str_replace('###TYPE###', $edittype, $message);
64        $message = str_replace('###SUMMARY###', $event->data['summary'], $message);
65
66        if (!isset($_SERVER['REMOTE_USER'])) {
67            switch ($this->getConf('guestIP')) {
68            case 'show': $message = str_replace('###EDITOR###', $_SERVER['REMOTE_ADDR'], $message);
69                break;
70            case 'alt' :
71                if(!plugin_isdisabled('hidingip')) {
72                    $hidingip = plugin_load('helper', 'hidingip');
73                    $message = str_replace('###EDITOR###', $hidingip->altText(), $message);
74                    break;
75                }
76                // Else, fall through
77            default    : $message = str_replace('###EDITOR###', '', $message);
78            }
79        } else $message = str_replace('###EDITOR###', userlink(null, true), $message);
80
81        $pageurl = wl($savingid, '', TRUE);
82
83        if (strpos($message, '###PAGEURL###') === FALSE) $message .= ' ' . $pageurl; else $message = str_replace('###PAGEURL###', $pageurl, $message);
84
85        // Insert a space after "@" not to violent the Twitter rule that prohibits "automated @ tweets"
86        $message = str_replace('@', '@ ', $message);  // one-byte @
87        $message = str_replace('@', '@ ', $message);  // two-byte @
88
89        // Copied and adoped from the reference above
90        //
91        // Parameter A (the option of the request)
92        $params_a = array(
93            'status' => $message ,
94        ) ;
95
96        // Make a key (URL encode)
97        $signature_key = rawurlencode( $api_secret ) . '&' . rawurlencode( $access_token_secret ) ;
98
99        // Parameter B (ingredients of the signature)
100        $params_b = array(
101            'oauth_token' => $access_token ,
102            'oauth_consumer_key' => $api_key ,
103            'oauth_signature_method' => 'HMAC-SHA1' ,
104            'oauth_timestamp' => time() ,
105            'oauth_nonce' => microtime() ,
106            'oauth_version' => '1.0' ,
107        ) ;
108
109        // Make parameter C by merging A and B
110        $params_c = array_merge( $params_a , $params_b ) ;
111
112        // Sort the associative array in alphabetical order
113        ksort( $params_c ) ;
114
115        // Convert the associative array of parameters into the string [key=value&key=value...]
116        $request_params = http_build_query( $params_c , '' , '&' ) ;
117
118        // Follow some characters
119        $request_params = str_replace( array( '+' , '%7E' ) , array( '%20' , '~' ) , $request_params ) ;
120
121        // URL-encode the converted string
122        $request_params = rawurlencode( $request_params ) ;
123
124        // URL-encode the request method
125        // In this time, it sholdn't include [?] in the last of the URL and after
126        $encoded_request_method = rawurlencode( $request_method ) ;
127
128        // URL-encode the request URL
129        $encoded_request_url = rawurlencode( $request_url ) ;
130
131        // Merge the request method, the request URL, and the parameters by [&]
132        $signature_data = $encoded_request_method . '&' . $encoded_request_url . '&' . $request_params ;
133
134        // Using the key [$signature_key] and the data [$signature_data], make a HMAC-SHA1 type hash value
135        $hash = hash_hmac( 'sha1' , $signature_data , $signature_key , TRUE ) ;
136
137        // Base64-encode, and the [$signature] is ready
138        $signature = base64_encode( $hash ) ;
139
140        // Add the signature to the associative array of the data [$params]
141        $params_c['oauth_signature'] = $signature ;
142
143        // Convert the associative array of the parameter into the string [key=value&key=value...]
144        $header_params = http_build_query( $params_c , '' , ',' ) ;
145
146        // Context for the request
147        $context = array(
148            'http' => array(
149                'method' => $request_method , // Request method
150                'header' => array(			  // Header
151                    'Authorization: OAuth ' . $header_params ,
152                ) ,
153            ) ,
154        ) ;
155
156        // If there is an option, make a POST field into the context
157        if ( $params_a ) {
158            $context['http']['content'] = http_build_query( $params_a ) ;
159        }
160
161        // Request by using cURL
162        $this->curl = curl_init() ;
163        curl_setopt( $this->curl, CURLOPT_URL , $request_url ) ;	// Request URL
164        curl_setopt( $this->curl, CURLOPT_HEADER, true ) ;	// Get the header
165        curl_setopt( $this->curl, CURLOPT_CUSTOMREQUEST, $context['http']['method'] ) ;	// Method
166        curl_setopt( $this->curl, CURLOPT_SSL_VERIFYPEER, false ) ;	// Don't verify the certificate
167        curl_setopt( $this->curl, CURLOPT_RETURNTRANSFER, true ) ;	// Return the result of the curl_exec with a string
168        curl_setopt( $this->curl, CURLOPT_HTTPHEADER, $context['http']['header'] ) ;	// Header
169        if( isset( $context['http']['content'] ) && !empty( $context['http']['content'] ) ) {
170            curl_setopt( $this->curl, CURLOPT_POSTFIELDS, $context['http']['content'] ) ;	// Request body
171        }
172        curl_setopt( $this->curl, CURLOPT_TIMEOUT, 5 ) ;	// Timeout seconds
173        $res1 = curl_exec( $this->curl ) ;
174        $res2 = curl_getinfo( $this->curl ) ;
175        curl_close( $this->curl ) ;
176
177        $json = substr( $res1, $res2['header_size'] ) ;	// Got data (such as JSON)
178        $header = substr( $res1, 0, $res2['header_size'] ) ;	// Response header
179
180        if ($this->getConf('debug') and auth_ismanager()) {
181            msg('[Debug] Body(JSON): ' . $json);
182            msg('[Debug] Response header: ' . $header);
183        }
184
185    }
186
187
188}