First Google+ (Google Plus) status update bot in PHP

Finally! Google Plus status updater is here :) It is written in PHP, so it should be cross platform, which is a plus ;) It needs the curl extension to work though. Well, the bot can log into your Google account and update your Google Plus status, but I’m sure you can extend it to other Google products. All this is done without Google API, OAuth, tokens or any other annoying products. Post your comments, improvements and feature request below.

Download: gplus-bot

<?php

/**
 * Google+ (plus.google.com) PHP Curl bot
 * @since Sep 29 2011
 * @version 15.12.2011
 * @link http://360percents.com/
 * @author Luka Pušić <luka@pusic.si>
 */
/**
 * REQUIRED PARAMETERS
 */
$status = 'testzzz';
$email = 'your@email.com';
$pass = 'yourpassw0rd';

/**
 * OPTIONAL PARAMETERS
 * sleeptime is an optional timeout parameter which makes us look less suspicious to Google
 * Enter pageid if you want to post to a page.
 */
$pageid = false;
$cookies = 'cookie.txt';
$sleeptime = 0;
$uagent = 'Mozilla/4.0 (compatible; MSIE 5.0; S60/3.0 NokiaN73-1/2.0(2.0617.0.0.7) Profile/MIDP-2.0 Configuration/CLDC-1.1)';
$pc_uagent = 'Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1';
$debug = FALSE;

function tidy($str) {
    return rtrim($str, "&");
}

/**
 * Handle cookie file
 */
@unlink($cookies); //delete previous cookie file if exists
touch($cookies); //create a cookie file

/**
 * MAIN BLOCK
 * login_data() just collects login form info
 * login($postdata) logs you in and you can do pretty much anything you want from here on
 */
login(login_data());
sleep($sleeptime);
if ($pageid) {
    update_page_status();
} else {
    update_profile_status();
} //update status with $GLOBAL['status'];
sleep($sleeptime);
logout(); //optional - log out

/**
 * 1. GET: http://plus.google.com/
 * Parse the webpage and collect form data
 * @return array (string postdata, string postaction)
 */
function login_data() {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_COOKIEJAR, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_USERAGENT, $GLOBALS['uagent']);
    curl_setopt($ch, CURLOPT_URL, "https://plus.google.com/app/basic/login");
    curl_setopt($ch, CURLOPT_COOKIEFILE, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

    $buf = utf8_decode(html_entity_decode(curl_exec($ch)));
    $buf = str_replace( '&', '&', $buf ); // just in case any correctly encoded
    $buf = str_replace( '&', '&', $buf ); // now encode them all again
    curl_close($ch);

    echo "\n[+] Sending GET request to: https://plus.google.com/app/basic/login\n\n";

    $toreturn = '';

    $doc = new DOMDocument;
    $doc->loadxml($buf);
    $inputs = $doc->getElementsByTagName('input');
    foreach ($inputs as $input) {
	switch ($input->getAttribute('name')) {
	    case 'Email':
		$toreturn .= 'Email=' . urlencode($GLOBALS['email']) . '&';
		break;
	    case 'Passwd':
		$toreturn .= 'Passwd=' . urlencode($GLOBALS['pass']) . '&';
		break;
	    default:
		$toreturn .= $input->getAttribute('name') . '=' . urlencode($input->getAttribute('value')) . '&';
	}
    }
    return array(tidy($toreturn), $doc->getElementsByTagName('form')->item(0)->getAttribute('action'));
}

/**
 * 2. POST login: https://accounts.google.com/ServiceLoginAuth
 */
function login($postdata) {

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_COOKIEJAR, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_USERAGENT, $GLOBALS['uagent']);
    curl_setopt($ch, CURLOPT_URL, $postdata[1]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata[0]);
    $buf = curl_exec($ch); #this is not the g+ home page, because the b**** doesn't redirect properly
    curl_close($ch);
    if ($GLOBALS['debug']) {
	echo $buf;
    }

    echo "\n[+] Sending POST request to: " . $postdata[1] . "\n\n";
}

/**
 * 3. GET status update form:
 * Parse the webpage and collect form data
 */
function update_profile_status() {

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_COOKIEJAR, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_USERAGENT, $GLOBALS['uagent']);
    curl_setopt($ch, CURLOPT_URL, 'https://m.google.com/app/plus/?v=compose&group=m1c&hideloc=1');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    $buf = utf8_decode(html_entity_decode(str_replace('&', '', curl_exec($ch))));
    $header = curl_getinfo($ch);
    curl_close($ch);
    if ($GLOBALS['debug']) {
	echo $buf;
    }

    $params = '';
    $doc = new DOMDocument;
    $doc->loadxml($buf);
    $inputs = $doc->getElementsByTagName('input');
    foreach ($inputs as $input) {
	if (($input->getAttribute('name') != 'editcircles')) {
	    $params .= $input->getAttribute('name') . '=' . urlencode($input->getAttribute('value')) . '&';
	}
    }
    $params .= 'newcontent=' . urlencode($GLOBALS['status']);
    //$baseurl = $doc->getElementsByTagName('base')->item(0)->getAttribute('href');
    $baseurl = 'https://m.google.com' . parse_url($header['url'], PHP_URL_PATH);

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_COOKIEJAR, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_USERAGENT, $GLOBALS['uagent']);
    //delete group=b0& in the line below, to post just to your circles, not to public
    curl_setopt($ch, CURLOPT_URL, $baseurl . '?v=compose&group=m1c&group=b0&hideloc=1&a=post');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_REFERER, $baseurl . '?v=compose&group=m1c&group=b0&hideloc=1');
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
    $buf = curl_exec($ch);
    $header = curl_getinfo($ch);
    curl_close($ch);
    if ($GLOBALS['debug']) {
	echo $buf;
    }

    echo "\n[+] POST Updating status on: " . $baseurl . "\n\n";
}

/**
 * Not implemented yet!
 * just ignore this function for now
 */
function update_page_status() {

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_COOKIEJAR, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_USERAGENT, $GLOBALS['pc_uagent']);
    curl_setopt($ch, CURLOPT_URL, 'https://plus.google.com/u/0/b/' . $GLOBALS['pageid'] . '/');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    $buf = utf8_decode(html_entity_decode(str_replace('&', '', curl_exec($ch))));
    curl_close($ch);
    if ($GLOBALS['debug']) {
	echo $buf;
    }
}

/**
 * 3. GET logout:
 * Just logout to look more human like and reset cookie :)
 */
function logout() {
    echo "\n[+] GET Logging out: \n\n";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_COOKIEJAR, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $GLOBALS['cookies']);
    curl_setopt($ch, CURLOPT_USERAGENT, $GLOBALS['uagent']);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_URL, 'https://www.google.com/m/logout');
    $buf = curl_exec($ch);
    curl_close($ch);
    if ($GLOBALS['debug']) {
	echo $buf;
    }
}

?>

39 thoughts on “First Google+ (Google Plus) status update bot in PHP

  1. Sorry for lots of text… My $buf, $doc don’t have TagName(‘base’) and Attribute(‘href’)

    echo $buf:
    ===================%<===================

    Google Accounts

    Account

    Email:

    Password:

    Remember me

    copy;2011 Google

    ===================%<===================

        • I did some modifications, but the script is still in early alpha stages :) It works for me now though…

          There are currently two issues:
          -Mobile phone security confirmation must be disabled
          -Mobile Google+ location terms of agreement must be accepted, which can be done once manually by visiting G+ on a phone (or fake the useragent in a browser)

          • PHP Fatal error: Call to a member function getAttribute() on a non-object in /home/****/tmp/gplus/gplus2.php on line 145

            Still doesn’t work for me.. Tried both turning on and off 2-step auth, tried both touch/basic mobile versions of the site. Anyway, can’t pass this authentication.

            Thanks for commiting to git this script )

            How do you use it? What links do you visit before launching the PHP? Do you have 2-step authorization? Does it work only for regular accounts (*@gmail.com) or for GoogleAps accounts too (*@mydomain.com)? What rows do you have in your cookie?

          • 1.) Two step verification must be turned off, of course :)
            2.) It also works for GoogleApps.

            Fixed for now… I was getting the same error!
            Google removed “base href=…” element recently so I had to fix the script. $baseurl is now determined via curl_info(). It works for me again. I pushed the new version to GitHub and you can download it here too.

            Google+ is going through a lot of changes daily, so it might take a while before this code becomes stable. But i would be really happy to see someone join me on this project :)

  2. At last! Works for me )
    But still it’s a great security breach in turning off the 2-step auth.
    Promoted the GIT src to several people on stackoverflow.

  3. Works quite good! Thanks a lot!

    Only the visibility of the post is set to “limited”, which means, that it is only visible of members following me. Is it possible to set the visibility to “public”?

  4. The script is giving
    parse error, expecting `’)” on line 90

    What is needed to fix that or can you put up a new script?

  5. Hi, can you help me please, I have this error:

    Warning: DOMDocument::loadXML() [domdocument.loadxml]: EntityRef: expecting ‘;’ in Entity, line: 60 in /***/index.php on line 76

    Fatal error: Call to a member function getAttribute() on a non-object in /***/index.php on line 90

  6. @Vahe and anyone else having trouble, it’s down to & encoding on the google plus page that is first fetched, the & are not encoded right so DOMDocument can’t do it’s stuff. If you edit the code and change

    $buf = utf8_decode(html_entity_decode(curl_exec($ch)));
    curl_close($ch);

    to

    $buf = utf8_decode(html_entity_decode(curl_exec($ch)));
    $buf = str_replace( ‘&’, ‘&’, $buf ); // just in case any correctly encoded
    $buf = str_replace( ‘&’, ‘&’, $buf ); // now encode them all again
    curl_close($ch);

    That’ll do it… just in case wordpress messes with what I have entered the code is up here on github too https://github.com/pauly/gplus-bot/tree/patch-1

    @Luka thanks for this code it’s great.

  7. Hi guys.
    Pauly’s script is not working for me without adding
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    otherwise
    Curl-Error: SSL certificate problem, verify that the CA cert is OK.

    not sure whether more problems might come up

  8. HI,I don’t understand what this script do, can it add people in my circles automatically.
    Thanks in advance

  9. Thanks a lot ,,
    But please help me, I have this problem:
    Fatal error: Call to a member function getAttribute() on a non-object in /home/a4763597/public_html/gplus.php on line 92

    Please reply to me as fast as possible ..

    • Sorry,, I was change the URL from “https://plus.google.com/” to “https://accounts.google.com/ServiceLoginAuth?service=oz”
      becuse the first one is not work and give me this error:
      Fatal error: Call to a member function getAttribute() on a non-object in /home/a4763597/public_html/gplus.php on line 92

      So,, when I’m change it to the second one, it’s give me this error:
      Fatal error: Call to a member function getAttribute() on a non-object in /home/a4763597/public_html/gplus.php on line 92

      Please help me,, what can I do to make this script work for me?

  10. I was getting all the errors described above when trying to test on my Localhost Dev server, as soon as I uploaded to my live server, everything worked! Can’t wait for Post to Page to be fixed as well, thanks guys for the great contribution

  11. Is it possible to add a URL and Photo? On G+ I generally post a Link to my blog articles which then automatically show the Title, description and thumbnail image from my articles meta data. Using this script, if I simply pass in he URL of an article, it just post a text link to the article with no other data. Could someone possibly show how to enhance this to show image and data with Link? I am able to pass in a URL, Title, Description, and Image URL, I just do not know the format to pass them in?

  12. I’m having one problem, google says that i’m logging from a location unsual and asking my secondary email.

    It’s seems its because i’m not german, can you please tell me how to change the locale.

    • Please ignore the first comment, but now i have this error

      Warning: DOMDocument::loadXML() [domdocument.loadxml]: Input is not proper UTF-8, indicate encoding ! Bytes: 0xED 0×72 0×63 0×75 in Entity, line: 1 in gplus.php on line 140

      I’ve replaced with Paulys code but does’t post status, I can log in no problems there

  13. Hello,

    If there is any idea to include the html message to g+ via this script…Its very urgent.. This script shows only the text content..Plz help .. Waiting for a solution…

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>