logo
Published on

โปรเจค Facebook Auto Like ทำงานอย่างไร

Authors
  • avatar
    Name
    Samiti
    Twitter

เกริ่น

ช่วงปี 2560 ได้สร้าง script การทำงานบนเว็บไซต์ที่เขียนด้วยภาษา PHP ในบทความนี้จะมาให้ความรู้ว่าระบบกดไลค์อัติโนมัติทำงานอย่าง เพื่อเป็นวิทยาทานสำหรับคนที่สนใจ code จะย่อโครงสร้างให้สั้นกระชับ แต่จริงๆ มีอีกเยอะมาก ดังนั้นบทความนี้จะเป็นเพียงไกค์ไลน์เท่านั้น โดยภาพรวมคือการเขียน PHP ยิงผ่าน facebook api Facebook API เพื่อที่เราจะสามารถใช้ API กดไลค์ได้ หรือนำไปเพิ่มไลค์ให้แก่คนอื่น

หากใครยังไม่ได้เป็น facebook developer รบกวนสมัครก่อนใช้งาน

ภาพรวมระบบกดไลค์

การกดไลค์อัติโนมัติคือ การเอา Token ของผู้ใช้งาน โดยจะมีลักษณะเป็นตัวอักขระผสมกันยาว ๆ นำมาป้อนตอนยิงฟังชั่นกดไลค์ผ่าน API ของเฟสบุ๊ค ดังนั้น พูดง่ายๆ ว่า เป็นเพียงแค่ การยิง request ผ่าน post บน Facebook API เท่านั้น เพื่อให้บัญชีผู้ใช้ที่เราได้ Token มากดไลค์ใส่คนอื่นๆ

โดยนักพัฒนาสามารถเข้าชม API ที่เฟสุบ๊คให้บริการได้ที่ Facebook API

แต่มีข้อเสียคือ การจะได้ตัว Token นั้นต้องได้รับการยินยอมจากบัญชีผู้ใช้งานคนๆ นั้น ในแง่มุมตรงนี้ผู้พัฒนาแอปจำเป็นต้องให้ทางผู้ใช้งาน copy token ดังกล่าวแล้ว ป้องเข้ามาใน Input ฟอร์มที่เตรียมไว้ให้

สำหรับการเขียน เราจะทำกันเพียงแค่ 2 ไฟล์ แต่ในโปรเจคทำงานจริงๆ เราทำงานในหลายองค์กรประกอบ ดังนั้นจะดึงเฉพาะส่วนที่เกี่ยวข้อง ดังต่อไปนี้

  1. facebook.php
  2. likes.php

โดยเราจะเขียน PHP Object บน facebook.php เพื่อใช้เป็นก้อน Object ตั้งค่าข้อมูลที่ต้องใช้และให้ likes.php เพื่อทำเป็นฟังชั่นบริการกดไลค์บน web application ของเรา

สร้างระบบกดไลค์

  1. สร้างคลาส abstract class Facebook โดยอย่างลืมลากก้อน Exception มาด้วยเพื่อได้ใช้งาน
abstract class BaseFacebook
{
    ....
}
  1. property สร้างตามรูปด้านล่าง
  protected $appId;
  protected $apiSecret;
  protected $accessToken = null;

  1. อย่าลืมเพิ่ม construct
  public function __construct($config) {
    $this->setAppId($config['appId']);
    $this->setApiSecret($config['secret']);
  }
  1. get set แต่ละตัวให้ครบตามตัวอย่าง

  public function setAppId($appId) {
    $this->appId = $appId;
    return $this;
  }

  public function getAppId() {
    return $this->appId;
  }

  public function setApiSecret($apiSecret) {
    $this->apiSecret = $apiSecret;
    return $this;
  }

  public function getApiSecret() {
    return $this->apiSecret;
  }

    public function setAccessToken($access_token) {
    $this->accessToken = $access_token;
    return $this;
  }

  public function getAccessToken() {
    if ($this->accessToken !== null) {
      return $this->accessToken;
    }

    $this->setAccessToken($this->getApplicationAccessToken());
    if ($user_access_token = $this->getUserAccessToken()) {
      $this->setAccessToken($user_access_token);
    }
    return $this->accessToken;
  }

  1. สร้าง service บริการผ่าน api

โดยเริ่มจากฟังชั่นสำหรับยิง Request API ชื่อ _restserver ด้านล่างนี้เป็น service สำหรบเรียกการยิง API

  public function api(/* polymorphic */) {
    $args = func_get_args();
    if (is_array($args[0])) {
      return $this->_restserver($args[0]);
    } else {
      return call_user_func_array(array($this, '_graph'), $args);
    }
  }

func_get_args() จะรวบอาร์กิวเมนต์ที่ตรงเข้ามาในฟังชั่นทั้งหมดมา อ้างอิง

  protected function _restserver($params) {
    $params['api_key'] = $this->getAppId();
    $params['format'] = 'json-strings';

    $result = json_decode($this->_oauthRequest(
      $this->getApiUrl($params['method']),
      $params
    ), true);

    if (is_array($result) && isset($result['error_code'])) {
      throw new FacebookApiException($result);
    }

    return $result;
  }

สำหรับ Object FacebookApiException สามารถเขียนได้ตามด้านล่าง หากพอใจตรงไหนก็ปรับเปลี่ยนได้ตามต้องการ เพียงหลักการง่าย ๆ คือ ตอน throw Error ให้ส่ง error_code เข้ามา

class FacebookApiException extends Exception
{
  protected $result;

  public function __construct($result) {
    $this->result = $result;

    $code = isset($result['error_code']) ? $result['error_code'] : 0;

    if (isset($result['error_description'])) {
      $msg = $result['error_description'];
    } else if (isset($result['error']) && is_array($result['error'])) {
      $msg = $result['error']['message'];
    } else if (isset($result['error_msg'])) {
      $msg = $result['error_msg'];
    } else {
      $msg = 'Unknown Error. Check getResult()';
    }

    parent::__construct($msg, $code);
  }

อธิบายการทำงานคือ _oauthRequest รับช่องพารามิเตอร์ api url กับ คิวรี่พารามิเตอร์ เพื่อจุดประสงค์คือ ตรวจหาว่า access_token อยู่หรือไม่ ถ้าไม่ก็ตั้งค่าใหม่

และที่สำคัญคือ encode ทุกตัวเป็น json string

  protected function _oauthRequest($url, $params) {
    if (!isset($params['access_token'])) {
      $params['access_token'] = $this->getAccessToken();
    }

    foreach ($params as $key => $value) {
      if (!is_string($value)) {
        $params[$key] = json_encode($value);
      }
    }

    return $this->makeRequest($url, $params);
  }

จะสังเกตว่าในคลาสก้อนนี้มี makeRequest() ที่รับเอา urlและurl และ params ตรงนี้เป็นการ Request ธรรมดาขึ้นอยู่แต่ละคน แน่นอนตัวเลือกของ PHP คือเรียกใช้ curl สามารถดูเพิ่มเติมได้ ที่นี่

ตัวอย่าง makeRequest

  protected function makeRequest($url, $params, $ch=null) {
    if (!$ch) {
      $ch = curl_init();
    }

    $opts = self::$CURL_OPTS;
    $opts[CURLOPT_URL] = $url;

    if (isset($opts[CURLOPT_HTTPHEADER])) {
      $existing_headers = $opts[CURLOPT_HTTPHEADER];
      $existing_headers[] = 'Expect:';
      $opts[CURLOPT_HTTPHEADER] = $existing_headers;
    } else {
      $opts[CURLOPT_HTTPHEADER] = array('Expect:');
    }

    curl_setopt_array($ch, $opts);

    $result = curl_exec($ch);

    if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT
      self::errorLog('Invalid or no certificate authority found, '.
                     'using bundled information');
      curl_setopt($ch, CURLOPT_CAINFO,
                  dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
      $result = curl_exec($ch);
    }

    if ($result === false) {
      $e = new FacebookApiException(array(
        'error_code' => curl_errno($ch),
        'error' => array(
        'message' => curl_error($ch),
        'type' => 'CurlException',
        ),
      ));
      curl_close($ch);
      throw $e;
    }
    curl_close($ch);
    return $result;
  }

  1. ขั้นตอนสุดท้ายนั้นก็คือ การเรียกใช้ Service จนกระทั่งผมได้ค้นพบวิธีใหม่และดีกว่าเดิมคือ โดยในไฟล์นี้ให้ตั้งชื่อ likes.php

ขั้นแรก เรียกไฟล์ facebook.php แล้วต่อดาต้าเบส

require 'include/facebook.php';

$token  = $_GET["accesstoken"];

$host = "localhost";
$username = "xxxxxxxxxxx";
$password = "xxxxxxxxxxx";
$dbname = "xxxxxxxxxxx";

mysql_connect($host,$username,$password) or die(mysql_error());
mysql_select_db($dbname) or die(mysql_error());
mysql_query("SET NAMES utf8");
$result = mysql_query("SELECT * FROM Likers ORDER BY RAND() LIMIT ".$likelimit);

แล้วเรียกก้อนที่เราสร้างมาเมื่อขั้นตอนก่อนหน้า และอย่าลืมสร้างตัวแปรต่างๆ ที่เราอาจจะใช้งาน

.....
$output = '';
$total = 0;

$facebook = new Facebook(array(
  'appId'  => $fb_app_id,
  'secret' => $fb_secret
));

ต่อดาต้าเบส แล้วสร้างตัวแปรพวกนี้ result และ Access Token ของผู้ใช้งานคนนั้นออกมากเพิ่ม ในก้อน $facebook->setApiSecret();

จากนั้นก็ยิงก้อน $facebook->api() ตามปกติ


  if($result){
      while($row = mysql_fetch_array($result, MYSQL_ASSOC)){
			$m = $row['access_token'];
			$facebook->setAccessToken ($m);
			$id = trim($_POST ['postid']);
			try {
				$facebook->api("/".$id."/likes", 'POST');
				$total++;
			}
		   catch (FacebookApiException $e) {
				$output .= "<p>'". $row['name'] . "' failed to like.</p>";
			}
	  }
			flush();
		}
		mysql_close();
		mysql_connect($host,$username,$password) or die(mysql_error());
		mysql_select_db($dbname) or die(mysql_error());
		mysql_query("INSERT INTO `like_queue` SET `post_id` = '".trim(mysql_real_escape_string($_POST['postid']))."',`like_limit` = '".$likelimit."',`done` = '".$total."',`ip` = '".$_SERVER['REMOTE_ADDR']."',`time` = '".time()."';");
		echo "<script>alert('คุณสุ่มไลท์ได้ทั้งหมด ".$total." ไลค์');</script>";
		mysql_close();

ในท้ายๆ บรรทัดอย่าลืมปิดฐานข้อมูลด้วย หากไม่ใช้งานแล้ว และบันทึกข้อมูลการใช้งานแต่ละบัญชีว่ากดไลค์ไปเท่านั้น เพื่อที่เราจะได้นำมาคำนวณในภายหลัง