Facebook Twitter Gplus RSS
Home Linux programs First Google+ (Google Plus) status update bot in PHP
formats

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/");
    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/\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;
    }
}

?>

 
 Share on Facebook Share on Twitter Share on Reddit Share on LinkedIn
33 Comments  comments 

33 Responses

  1. Sweet! Testing it.
    The script needs some modification, I’m working on it.

    [+] Sending GET request to: https://plus.google.com/
    [+] Sending POST request to: https://accounts.google.com/ServiceLoginAuth
    PHP Fatal error: Call to a member function getAttribute() on a non-object in /home/******/****/gplus/gplus.php on line 126

  2. 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

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

  3. Oops.. All html was cut out by WP.
    Here’s my $buf: http://pastie.org/2798063

  4. Very good script, it works perfect after some modifications ! Thanks a lot

    • Can you please submit the modifications? It would save me some time. Thank you

      • I would also like to hear about modifications.
        Still doesn’t work for me.

        • 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)

          • klisanor

            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 :)

  5. klisanor

    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.

  6. Doesn’t work for me any more
    https://m.google.com/app/plus/?v=compose&group=m1c&hideloc=1 is now gone, its now being pasted to https://m.google.com/app/plus/mp/165/data with plain POST. And although I manage to post fake data and accept result with weird “while” cycles in there.. it doesn’t show up.

    Also, on my hosting CURLOPT_FOLLOWLOCATION was disabled because of safe mode.

  7. mt

    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”?

  8. Richard

    have you found a solution for update_page_status this time?

  9. jeff

    is there an API to post the status update?

  10. myquestion

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

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

  11. Vahe Israyelyan

    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

  12. @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.

  13. Yeah wordpress messed with my code above and changed all the & amp ; to just & again so follow the github link…

  14. df

    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

  15. Dani

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

  16. Amer

    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 ..

    • Amer

      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?

  17. 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

  18. 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?

  19. Bruno

    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.

    • Bruno

      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

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>