Skip to content

Instantly share code, notes, and snippets.

@nishad
Created October 3, 2016 03:04
Show Gist options
  • Save nishad/86850f50ea7397fcb1c1e3076590b4f7 to your computer and use it in GitHub Desktop.
Save nishad/86850f50ea7397fcb1c1e3076590b4f7 to your computer and use it in GitHub Desktop.
<?php
/**
* cURL
*
* @author CertaiN
* @github https://github.com/Certainist/cURL
* @license BSD 2-Clause
*/
class cURL implements Serializable {
/**
* Default User-Agent.
*
* @static
* @access public
*/
public static $defaultUserAgent = 'Chrome';
private $ch;
private $fp;
private $userAgent;
private $cookie;
/**
* You have to call parent::__construct() on your extended method.
*
* @magic
* @access public
* @param string [$user_agent = null]
*/
public function __construct($user_agent = null) {
$list = static::getUserAgents();
if (!func_num_args()) {
$user_agent = static::$defaultUserAgent;
}
if (!is_string($user_agent)) {
throw new InvalidArgumentException('User-Agent value type must be string.');
}
if (!is_array($list)) {
throw new DomainException('static::getUserAgents() must return 1 dimentional assoc.');
}
if (!array_key_exists($user_agent, $list)) {
throw new InvalidArgumentException('Unknown User-Agent.');
}
if (!is_string($list[$user_agent])) {
throw new DomainException('static::getUserAgents() return array must contain string values.');
}
$this->userAgent = $list[$user_agent];
$this->init();
}
/**
* For GET requests.
*
* @access public
* @param string $url
* @param mixed [&$info = null] Set result of curl_getinfo().
* @return string Response body.
*/
public function get($url, &$info = null) {
if (!is_string($url)) {
throw new InvalidArgumentException('URL value type must be string.');
}
if (!is_resource($this->ch)) {
throw new BadMethodCallException('cURL resource is not initialized');
}
curl_setopt_array($this->ch, array(
CURLOPT_URL => $url,
CURLOPT_HTTPGET => true,
));
return $this->exec($info);
}
/**
* For POST requests.
*
* @access public
* @param string $url
* @param mixed $params Query string or associative array.
* @param mixed [&$info = null] Set result of curl_getinfo().
* @return string Response body.
*/
public function post($url, $params, &$info = null) {
if (!is_string($url)) {
throw new InvalidArgumentException('URL value type must be string.');
}
if (!is_resource($this->ch)) {
throw new BadMethodCallException('cURL resource is not initialized');
}
curl_setopt_array($this->ch, array(
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $params,
));
return $this->exec($info);
}
/**
* Clear cookies.
*
* @access public
*/
public function clearCookies() {
if (!is_resource($this->ch)) {
throw new BadMethodCallException('cURL resource is not initialized');
}
ftruncate($this->fp, 0);
}
/**
* Return the list of User-Agents.
* You can extend this method.
*
* @static
* @access protected
* @return array Associative array.
*/
protected static function getUserAgents() {
return array(
'Chrome' =>
'Mozilla/5.0 (Windows NT 6.1) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) ' .
'Chrome/28.0.1500.63 Safari/537.36'
,
'Firefox' =>
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) ' .
'Gecko/20100101 Firefox/9.0.1'
,
'Android' =>
'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03S) ' .
'AppleWebKit/535.19 (KHTML, like Gecko) ' .
'Chrome/18.0.1025.166 Safari/535.19'
,
'iOS' =>
'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) ' .
'AppleWebKit/536.26 (KHTML, like Gecko) ' .
'Version/6.0 Mobile/10A403 Safari/8536.25'
,
'Windows Phone' =>
'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; ' .
'Trident/5.0; IEMobile/9.0; ' .
'FujitsuToshibaMobileCommun; IS12T; KDDI)'
,
'Internet Explorer' =>
'Mozilla/5.0 (Windows NT 6.3; WOW64; ' .
'Trident/7.0; Touch; rv:11.0) like Gecko'
,
);
}
/**
* Serialize your own properties.
* You can extend this method.
*
* @access protected
* @return mixed
*/
protected function userSerialize() { return null; }
/**
* Unserialize your own properties.
* You can extend this method.
*
* @param anything $data
* @access protected
* @return mixed
*/
protected function userUnserialize($data) { }
/**
* You have to call parent::__destruct() on your extended method.
*
* @magic
* @access public
*/
public function __destruct() {
if (is_resource($this->ch)) {
curl_close($this->ch);
}
if (is_resource($this->fp)) {
$this->cookie = stream_get_contents($this->fp);
fclose($this->fp);
}
}
final public function serialize() {
$this->__destruct();
$this->init($this->cookie);
return serialize(array(
$this->userAgent,
$this->cookie,
$this->userSerialize(),
));
}
final public function unserialize($data) {
if (
!$data = @unserialize($data) or
!array_key_exists(0, $data) or
!array_key_exists(1, $data) or
!array_key_exists(2, $data) or
!in_array($data[0], static::getUserAgents(), true) or
!is_string($data[1])
) {
throw new UnexpectedValueException('Invalid serial');
}
$this->userAgent = $data[0];
$this->init($data[1]);
$this->userUnserialize($data[2]);
}
private function exec(&$info) {
$ret = curl_exec($this->ch);
$info = curl_getinfo($this->ch);
return $ret;
}
private function init($data = '') {
$this->fp = tmpfile();
if ($data !== '') {
fwrite($this->fp, $data);
rewind($this->fp);
}
$info = stream_get_meta_data($this->fp);
$cookie_uri = $info['uri'];
$this->ch = curl_init();
curl_setopt_array($this->ch, array(
CURLINFO_HEADER_OUT => true,
CURLOPT_AUTOREFERER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 15,
CURLOPT_MAXREDIRS => 5,
CURLOPT_COOKIEFILE => $cookie_uri,
CURLOPT_COOKIEJAR => $cookie_uri,
CURLOPT_ENCODING => 'gzip, deflate',
CURLOPT_USERAGENT => $this->userAgent,
CURLOPT_HTTPHEADER => array(
'Accept: ' .
'text/html,' .
'application/xhtml+xml,' .
'application/xml' .
';q=0.9,*/*;q=0.8'
,
'Accept-Language: ' .
'ja,en-us;q=0.7,en;q=0.3'
,
),
));
}
}
@nishad
Copy link
Author

nishad commented Oct 3, 2016

Example with nicovideo

<?php 
require 'cURL.php';

class NicoNico extends cURL {

    public function __construct($mail_tel, $password) {
        parent::__construct('Chrome');
        $this->get('http://www.nicovideo.jp/login');
        $this->post(
            'https://secure.nicovideo.jp/secure/login?site=niconico',
            array(
                'next_url' => '',
                'mail_tel' => $mail_tel,
                'password' => $password,
            ),
            $info
        );
        if ($info['url'] !== 'http://www.nicovideo.jp/') {
            throw new RuntimeException('ログインに失敗しました');
        }
    }

    public function getHistory() {
        $regex = implode('.*?', array(
            '<div class="outer" id="outer_sm(\d*+)">',
            '<img src="([^"]*+)" alt="([^"]*+)" class="video" />',
            '<span class="videoTime">([^<]*+)</span>',
            '<p class="posttime">(\d*+年\d*+月\d*+日 \d*+:\d*+)',
            '<span>視聴回数(\d*+)回</span>',
            '<li class="play">再生:([^<]*+)</li>',
            '<li class="comment">コメント:([^<]*+)</li>',
            '<li class="mylist">マイリスト:<a href="[^"]*+">([^<]*+)</a></li>',
            '<li class="posttime">(\d*+年\d*+月\d*+日 \d*+:\d*+) 投稿</li>',
        ));
        $regex = "@{$regex}@s";
        $str = $this->get('http://www.nicovideo.jp/my/history');
        if (!preg_match_all($regex, $str, $matches, PREG_SET_ORDER)) {
            throw new RuntimeException('履歴取得に失敗しました');
        }
        foreach ($matches as $match) {
            $ret[] = array(
                'id' => $match[1],
                'url' => "http://www.nicovideo.jp/watch/sm{$match[1]}",
                'thumb_url' => $match[2],
                'title' => $match[3],
                'duraction' => $match[4],
                'watched_at' => $match[5],
                'watched_count' => $match[6],
                'meta_watched_count' => $match[7],
                'meta_comment_count' => $match[8],
                'meta_mylist_count' => $match[9],
                'meta_created_at' => "20{$match[10]}", 
            );
        }
        return $ret;
    }

}

$nico = new NicoNico('[email protected]', 'xxxxxxx');
var_dump($nico->getHistory());

Output

array(30) {
  [0]=>
  array(11) {
    ["id"]=>
    string(8) "21280725"
    ["url"]=>
    string(40) "http://www.nicovideo.jp/watch/sm21280725"
    ["thumb_url"]=>
    string(45) "http://tn-skr2.smilevideo.jp/smile?i=21280725"
    ["title"]=>
    string(69) "【オツキミリサイタル】歌ってみた @ゆいこんぬ"
    ["duraction"]=>
    string(4) "3:45"
    ["watched_at"]=>
    string(23) "2013年12月05日 14:10"
    ["watched_count"]=>
    string(1) "1"
    ["meta_watched_count"]=>
    string(7) "316,137"
    ["meta_comment_count"]=>
    string(5) "4,322"
    ["meta_mylist_count"]=>
    string(6) "14,802"
    ["meta_created_at"]=>
    string(23) "2013年07月05日 17:57"
  }
  [1]=>
  ....

It's possible to serialize and maintain Cookie just as it is.

file_put_contents('NicoNico.dat', serialize($nico));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment