Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
23 liveuser 1
<?php
2
 
3
/*
4
 
5
MIT License
6
 
7
Copyright (c) 2017 Galih Akbar Moerbayaksa
8
 
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
 
16
The above copyright notice and this permission notice shall be included in all
17
copies or substantial portions of the Software.
18
 
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
SOFTWARE.
26
 
27
*/
28
 
29
namespace Line;
30
 
31
class LineTimeline{
32
 
33
    private $line_host = 'https://timeline.line.me/api/';
34
    public $timeline_order = 'TIME'; // RANKING
35
    public $post_limit = 10;
36
    public $user;
37
    public $gnb;
38
    public $home_id;
39
    public $session_id;
40
 
41
    private $is_true_last = false;
42
    private $last_response = [];
43
 
44
    public function __construct(){
45
        // To do...
46
    }
47
 
48
    /*
49
        @title Set Session Cookies
50
        @param $ids string
51
        @return
52
    */
53
    public function setSession($ids){
54
        $this->session_id = $ids;
55
        return $this;
56
    }
57
 
58
    /*
59
        @title Set Type Order Untuk Timeline
60
        @param $param string
61
        @return
62
    */
63
    public function order($param){
64
        if(!in_array($param, ['TIME', 'RANKING'])) throw new Exception("Invalid Order Type");
65
        $this->timeline_order = $param;
66
    }
67
 
68
    /*
69
        @return
70
    */
71
    public function userinfo(){
72
        $this->sessID();
73
        $http = $this->response($this->http('gnb/userInfo.json'));
74
        if($this->isOK()){
75
            $data = [];
76
            $this->user = $http['userInfo'];
77
            $this->gnb = $http['gnb'];
78
            $this->home_id = $this->gnb['homeInfo']['homeId'];
79
            return $this;
80
        }
81
        else{
82
            throw new Exception('Invalid sesssion!');
83
        }
84
    }
85
 
86
    /*
87
        @title Get Latest Response if One
88
        @param
89
        @return
90
    */
91
    public function get(){
92
        return $this->last_response;
93
    }
94
 
95
    /*
96
        @title Get Notification
97
        @param
98
        @return
99
    */
100
    public function notification(){
101
        $http = $this->response($this->http('gnb/noticenter.json'));
102
        if($this->isOK()){
103
            return $http['notifications'];
104
        }
105
        else{
106
            throw new Exception('Invalid sesssion!');
107
        }
108
    }
109
 
110
    /*
111
        @title Get Friend List
112
        @param $total integer
113
        @param $callback callable
114
        @return
115
    */
116
    public function friendList($total, callable $callback = NULL){
117
        if(!is_numeric($total) OR $total <= 0) throw new Exception("Invalid total!");
118
        $multiple = ($total <= 20) ? 1 : ($total - ($total % 20)) / 20;
119
        if($total % 20 != 0) $multiple++;
120
        $tmp_arr = [];
121
        for($i=0;$i<$multiple;$i++){
122
            $scrool_id = ($i * 20) + 1;
123
            $this->getFriend($scrool_id, function($data) use (&$tmp_arr){
124
                if(empty($data) OR count($data) == 0) break;
125
                $tmp_arr = array_merge($tmp_arr, $data);
126
            });
127
        }
128
        $this->last_response = array_slice($tmp_arr, 0, $total);
129
        return ($this->_end($this->isOK(), $callback) == true);
130
    }
131
 
132
    /*
133
        @title Post Status to Timeline
134
        @param $text string
135
        @param $type integer
136
        @param $large_text boolean
137
        @param $callback callable
138
        @return
139
    */
140
    public function postTimeline($text, $type = 1, $large_text = false, $sticker = [], callable $callback = NULL){
141
        $this->sessId();
142
        /* Sticker example
143
        $sticker[] = ["id"=>5,"packageId"=>1,"packageVersion"=>100];
144
        $sticker[] = ["id"=>1,"packageId"=>1,"packageVersion"=>100];
145
        */
146
        switch($type){
147
            case 1:
148
                $permission = 'ALL';
149
                break;
150
            case 2:
151
                $permission = 'FRIEND';
152
                break;
153
            case 3:
154
                $permission = 'NONE';
155
                break;
156
            default:
157
                throw new Exception("Invalid post type!");
158
        }
159
        $large_text = ($large_text == true) ? 'true' : 'false';
160
        $stickers = json_encode($sticker);
161
        $post = '{"postInfo":{"readPermission":{"type":"'.$permission.'","gids":null}},"contents":{"text":"'.$text.'","largeText":'.$large_text.',"stickers":'.$stickers.',"media":[]}}';
162
        $http = $this->response($this->http('post/create.json?sourceType=TIMELINE ', $post));
163
        return ($this->_end($this->isOK(), $callback) == true);
164
    }
165
 
166
    /*
167
        @title Delete Comment by ID and Comment Id
168
        @param $postid string
169
    */
170
    public function deleteComment($postid, $commentid, callable $callback = NULL){
171
        $this->sessID();
172
        $post = '{"postId":"'.$postid.'","actorId":"x","commentId":"'.$commentid.'"}';
173
        $http = $this->response($this->http('post/delete.json?sourceType=TIMELINE&homeId=' . $this->home_id, $post));
174
        return ($this->_end($this->isOK(), $callback) == true);
175
    }
176
 
177
    /*
178
        @title Add Friend
179
        @param $homeid string
180
    */
181
    public function addFriend($homeid, callable $callback = NULL){
182
        $this->sessID();
183
        $post = '{"mid":"' . $homeid . '"}';
184
        $http = $this->response($this->http('friend/add.json', $post));
185
        return ($this->_end($this->isOK(), $callback) == true);
186
    }
187
 
188
    /*
189
        @title Delete Post by ID
190
        @param $postid string
191
    */
192
    public function deletePost($postid, callable $callback = NULL){
193
        $this->sessID();
194
        $post = '{"postId":"'.$postid.'"}';
195
        $http = $this->response($this->http('post/delete.json?sourceType=TIMELINE&homeId=' . $this->home_id, $post));
196
        return ($this->_end($this->isOK(), $callback) == true);
197
    }
198
 
199
    /*
200
        @title Get group list
201
        @param $limit integer
202
        $param $callback callable
203
    */
204
    public function groupList($limit = 100, callable $callback = NULL){
205
        $this->sessID();
206
        $http = $this->response($this->http('group/list.json?limit=' . $limit));
207
        $this->last_response = $http;
208
        return ($this->_end($this->isOK(), $callback) == true);
209
    }
210
 
211
    /*
212
        @title Search Post by Hashtag
213
        @param $hashtag string
214
        @param $limit integer
215
        $param $callback callable
216
    */
217
    public function searchByHashtag($hashtag, $limit = 10, callable $callback = NULL){
218
        $this->sessID();
219
        $http = $this->response($this->http('hashtag/search.json?query='.$hashtag.'&postLimit='.$limit.'&commentLimit=1&likeLimit=1'));
220
        $this->last_response = $http;
221
        return ($this->_end($this->isOK(), $callback) == true);
222
    }
223
 
224
    /*
225
        @title Comment a Post by Post ID
226
        @param $home_id string
227
        @param $post_id string
228
        @param $comment_text string
229
        @param $callback callable
230
        @return
231
    */
232
    public function commentPost($home_id, $post_id, $comment_text, callable $callback = NULL){
233
        $this->sessID();
234
        $post = '{"contentId":"'.$post_id.'","commentText":"'.$comment_text.'","contentsList":[],"actorId":"'.$this->home_id.'","recallInfos":[]}';
235
        $http = $this->response($this->http('comment/create.json?sourceType=MYHOME_END&homeId=' . $home_id, $post));
236
        return ($this->_end($this->isOK(), $callback) == true);
237
    }
238
 
239
    /*
240
        @title Like a Post by Post ID
241
        @param $post_id string
242
        @param $reaction integer
243
        @param $shareable boolean
244
        @param $callback callable
245
        @return
246
    */
247
    public function likePost($post_id, $reaction = 0, $shareable = false, callable $callback = NULL){
248
        $this->sessID();
249
        // 1 love 2 haha 3 ok 4 terharu 5 kaget 6 cry 0 random
250
        if(!in_array($reaction, [0,1,2,3,4,5,6])) throw new Exception('Invalid reaction id!');
251
        $shareable = ($shareable == true) ? 'true' : 'false';
252
        if($reaction == 0) $reaction = mt_rand(1, 6);
253
        $post = '{"contentId":"'.$post_id.'","actorId":"x","likeType":"100'.$reaction.'","sharable":'.$shareable.'}';
254
        $http = $this->response($this->http('like/create.json?sourceType=TIMELINE&homeId=x', $post));
255
        return ($this->_end($this->isOK(), $callback) == true);
256
    }
257
 
258
    /*
259
        @title Cancel Like a Post by Post ID
260
        @param $post_id string
261
        @param $callback callable
262
        @return
263
    */
264
    public function unlikePost($post_id, callable $callback = NULL){
265
        $this->sessID();
266
        $post = '{"contentId":"'.$post_id.'"}';
267
        $http = $this->response($this->http('like/cancel.json?sourceType=TIMELINE&homeId=x', $post));
268
        return ($this->_end($this->isOK(), $callback) == true);
269
    }
270
 
271
    /*
272
        @title Like Timeline (This Session)
273
        @param $max integer
274
        @param $reaction integer
275
        @param $mode integer
276
        @param $share_mode integer
277
        @param $callback callable
278
        @return
279
    */
280
    public function likeTimeline($user = NULL, $max = 1, $reaction = 0, $mode = 1, $share_mode = 1, callable $callback = NULL){
281
        $this->sessID();
282
        if(!in_array($mode, [1,2,3])) throw new Exception('Invalid mode!');
283
        if(!in_array($share_mode, [1,2,3,4])) throw new Exception('Invalid share mode!');
284
        if(!in_array($reaction, [0,1,2,3,4,5,6])) throw new Exception('Invalid reaction id!');
285
        $this->getHomeList($user, function($timeline) use ($max, $reaction, $mode, $share_mode, $callback){
286
            $n = 0;
287
            if(is_array($timeline) && count($timeline) > 0){
288
                foreach($timeline as $tl){
289
                    if($n >= $max) break;
290
                    if($reaction == 0) $reaction = mt_rand(1, 6);
291
                    $post_d = $tl['post']['postInfo']['postId'];
292
                    $liked = $tl['post']['postInfo']['liked'];
293
                    if($liked == false && $this->isPassLikesMode($tl, $mode)){
294
                        $this->likePost($post_d, $reaction, $this->isShareableMode($tl, $share_mode), $callback);
295
                        $n++;
296
                    }
297
                }
298
                return $this;
299
            } else {
300
                throw new Exception("Error occured!");
301
            }
302
        });
303
    }
304
 
305
    private function getFriend($scrool_id = 1, callable $callback = NULL){
306
        $http = $this->response($this->http('friend/list.json?scrollId='.$scrool_id.'&limit=20'));
307
        if($this->isOK()){
308
            if(empty($http['friends'])) throw new Exception('Invalid response data!');
309
            if(is_callable($callback) && $callback != NULL){
310
                $callback($http['friends']);
311
            }
312
            else {
313
                return $http['friends'];
314
            }
315
        }
316
        else {
317
            throw new Exception('Invalid session data!');
318
        }
319
    }
320
 
321
    private function getHomeList($user_id = NULL, callable $callback = NULL){
322
        // $user_id example : _dQXvILQLzuN5-jSNMrfUNcemoCbkLSmRijRjFrU
323
        $this->sessID();
324
        if(empty($this->user)) $this->userinfo();
325
        if(empty($this->user) or empty($this->home_id)) throw new Exception('Invalid user info!');
326
        if($user_id == NULL){
327
            $http = $this->response($this->http('feed/list.json?postLimit='.$this->post_limit.'&commentLimit=2&likeLimit=20&order='.$this->timeline_order.'&requestTime=' . time()));
328
        }
329
        else {
330
            $http = $this->response($this->http('post/list.json?homeId='.$user_id.'&postLimit='.$this->post_limit.'&commentLimit=2&likeLimit=20&requestTime=' . time()));
331
        }
332
        if($this->isOK()){
333
            if(count($http['feeds']) < 1) throw new Exception('Invalid response data!');
334
            if(is_callable($callback) && $callback != NULL){
335
                $callback($http['feeds']);
336
            }
337
            else {
338
                return $http['feeds'];
339
            }
340
        }
341
        else {
342
            throw new Exception('Invalid session data!');
343
        }
344
    }
345
 
346
    private function is_official($data){
347
        if(!empty($data['post']['postInfo']['officialHome']['homeType']) && $data['post']['postInfo']['officialHome']['homeType'] == 'OFFICIAL'){
348
            return true;
349
        } else {
350
            return false;
351
        }
352
    }
353
 
354
    private function isPassLikesMode($data, $mode){
355
        switch($mode){
356
            case 1:
357
                return true;
358
                break;
359
            case 2: // User only
360
                if($this->is_official($data) == false){
361
                    return true;
362
                } else {
363
                    return false;
364
                }
365
                break;
366
            case 3: // line @ only
367
                if($this->is_official($data) == true){
368
                    return true;
369
                } else {
370
                    return false;
371
                }
372
                break;
373
            default:
374
                throw new Exception("Error occured!");
375
        }
376
    }
377
 
378
    private function isShareableMode($data, $mode){
379
        switch($mode){
380
            case 1: // dont share anything
381
                return false;
382
                break;
383
            case 2: // share anything
384
                return true;
385
                break;
386
            case 3: // share if user
387
                if($this->is_official($data) == false){
388
                    return true;
389
                } else {
390
                    return false;
391
                }
392
                break;
393
            case 4: // share if line @ account
394
                if($this->is_official($data) == true){
395
                    return true;
396
                } else {
397
                    return false;
398
                }
399
            default:
400
                throw new Exception("Error occured!");
401
        }
402
    }
403
 
404
    private function sessID(){
405
        if(empty($this->session_id)){
406
            throw new Exception("Please set session id first!");
407
        }
408
    }
409
 
410
    private function isOK(){
411
        return $this->is_true_last;
412
    }
413
 
414
    private function response($response, $return = false){
415
        $res = json_decode($response[1], true);
416
        if(!empty($res) && $res['message'] == 'success' && isset($res['result'])){
417
            $this->is_true_last = true;
418
        } else {
419
            $this->is_true_last = false;
420
        }
421
        if($this->is_true_last){
422
            return $res['result'];
423
        } else {
424
            return [];
425
        }
426
    }
427
 
428
    private function _end($isOK, $callback){
429
        if($isOK == true){
430
            if($callback != NULL && is_callable($callback)){
431
                $callback(false, $this);
432
            } else {
433
                return true;
434
            }
435
        } else {
436
            if($callback != NULL && is_callable($callback)){
437
                $callback(true);
438
            } else {
439
                return false;
440
            }
441
        }
442
    }
443
 
444
    private function http($path, $postdata = ''){
445
        $ch = curl_init();
446
        curl_setopt($ch, CURLOPT_URL, $this->line_host . $path);
447
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36');
448
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
449
        curl_setopt($ch, CURLOPT_VERBOSE, false);
450
        curl_setopt($ch, CURLOPT_ENCODING , "gzip");
451
        curl_setopt($ch, CURLOPT_HTTPHEADER, $this->getHeaderList($postdata));
452
        if(!empty($postdata)){
453
            curl_setopt($ch, CURLOPT_POST, true);
454
            curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
455
        }
456
        $response = curl_exec($ch);
457
        $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
458
        curl_close($ch);
459
 
460
        return array($http, $response);
461
    }
462
 
463
    private function getHeaderList($p){
464
        $ht = 'Host: timeline.line.me
465
            Connection: keep-alive
466
            Accept: application/json, text/plain, */*
467
            X-Timeline-WebVersion: 1.4.2
468
            X-Line-AcceptLanguage: en
469
            User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
470
            Origin: https://timeline.line.me
471
            Content-Type: application/json;charset=UTF-8
472
            Referer: https://timeline.line.me/
473
            Accept-Encoding: gzip, deflate, br
474
            Accept-Language: en,id;q=0.8,ja;q=0.6
475
            Cookie: tc="'.$this->session_id.'";';
476
        if(!empty($p) && strlen($p) > 0){
477
            $ht .= "\nContent-Length: " . strlen($p);
478
        }
479
        return array_map(function($val){
480
            return trim($val);
481
        }, explode("\n", $ht));
482
    }
483
}
484
 
485
/* post 文字
486
$app = new LineTimeline();
487
$app->setSession('COOKIESHERE');
488
$app->postTimeline('Hehehehe, welcome AskaEks', 1, false);
489
*/