jc21 / plex-api

PHP API for Plex Servers
Other
35 stars 8 forks source link

Returns boolean(false) when try to auth to plex.tv #8

Open vladshoob opened 6 years ago

vladshoob commented 6 years ago

Good time of yours,

thanks for your work, and if I could on my own, I would gladly solve this and contribute. But I can't figure out what is wrong.

For some reason, I can not login to plex.tv, so that login call return empty response.

Maybe POST params for login has been changed.

lhilton commented 6 years ago

I just confirmed that I CAN auth with the current version of the code.

Are you able to show a code snippet of how you are trying to use the lib?

vladshoob commented 6 years ago

$client = new PlexApi(LOCAL_SERVER_IP, LOCAL_SERVER_PORT, IS_LOCAL_SERVER_HTTPS); $client->setAuth(LOGIN, PASSWORD); $output = $client->getBaseInfo(); dd($output);

It is as in basic examples. Seems like I am receiving an empty response with login post curl.

I did face the very similar issue, but not with my PC or provider some days ago. I have tried to solve why file_get_contents($path) (or curl as well) receives empty response body ("") from graph facebook after theirs 'terms of use' update.

vladshoob commented 6 years ago

Hm, it is ok now =(

Probably I just had my plex media server closed or something like that.

Any ideas how to call plex.tv for info, instead of local server?

Thanks in advance!

delovelady commented 2 years ago

I experience the same issue, more often than not.

Here is the code:

#!/usr/bin/env php
<?php

define('FAVORITES_TITLE', 'Share Favorites') ;
define('GENERAL_TITLE', 'Movies') ;
define('PLEX_DATABASE_SERVER', 'web') ;
define('PLEX_HOST', 'r2d2.lovelady.com') ;

//######################################################################################
// https://github.com/jc21/plex-api/blob/master/docs/Documentation.md
//######################################################################################

require_once('lovefunctions.php') ;
require_once('vendor/autoload.php') ;

use jc21\PlexApi ;
use jc21\Util\Filter ;

$pdo = $lov->pdoConnect(PLEX_DATABASE_SERVER) ;
// Get the latest login credentials for this host
$sql = <<<EOS
            SELECT cred.hostname, effective, userId, password
            FROM   plexCredentials cred
            WHERE  cred.hostname = ?
               AND effective <= CURRENT_TIMESTAMP
            ORDER BY effective DESC
            LIMIT 1
            EOS ;
$getCredsStmt = $lov->pdoPrepare($pdo, $sql) ;
$getCredsStmt->execute( [ PLEX_HOST ] ) ;
$nbrRows = $getCredsStmt->rowCount() ;
if ($nbrRows == 0) {
    printf("Could not obtain PLEX credentials from database.\nSQL: %s", $getCredsStmt->queryString) ;
    exit(1) ;
    }
elseif ($nbrRows > 1) {
    printf("%d rows returned requesting PLEX credentials from database.\nSQL: %s", $nbrRows, $getCredsStmt->queryString) ;
    exit(1) ;
    }

$creds = $getCredsStmt->fetch(PDO::FETCH_ASSOC) ;
$client = new PlexApi($creds['hostname']);
$client->setAuth($creds['userId'], $creds['password'] ) ;
if (isset($creds['token']))
    $client->setToken($creds['token']) ;

for ($i=0; $i<10; $i++) { // Because sometimes the login just doesn't work, but after several retries all is well.
    $librarySections = $client->getLibrarySections();
    if (is_array($librarySections) && isset($librarySections['Directory']) && count($librarySections['Directory'])>0) {
        break ;
        }
    if ( ! ($token = $client->getToken()))
        printf("Login was not successful.\n") ;
    elseif ($debug)
        printf("No library sections found. (%d)\n", $i) ;
    }
if ( ! ($token = $client->getToken())) {
    printf("Unable to log in.\n") ;
    exit(1) ;
    }
printf("Logged in.\n") ;

And here is sample output from a few executions:

> testFavorite
Logged in.
dennis@r2d2:/www/ 10/20 13:28:27
> testFavorite
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Unable to log in.
dennis@r2d2:/www/ 10/20 13:28:45
> testFavorite
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Unable to log in.
dennis@r2d2:/www/ 10/20 13:28:58
> testFavorite
Login was not successful.
Login was not successful.  
Logged in.
dennis@r2d2:/www/ 10/20 13:29:09
> testFavorite
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Login was not successful.
Unable to log in.
dennis@r2d2:/www/ 10/20 13:29:20
> testFavorite
Logged in.

I don't know how to troubleshoot this, to figure out what's gone wrong. How can I diagnose this?

(To get around it, I have saved the token in the database and changed the SELECT accordingly...)

            SELECT cred.hostname, effective, userId, password, token

But it's a sad day when Plex invalidates the token, which it sometimes does.

delovelady commented 2 years ago

In addition, I found that when the login fails, this is not detected by PlexApi::call() so the latest curl result covers up the result from the failed login attempt. This code seems to resolve that issue (but of course not the login issue).

public function call($path, $params = [], $method = self::GET, $isLoginCall = false)
{
    if (!$this->token && !$isLoginCall) {
        $this->call('https://plex.tv/users/sign_in.xml', [], self::POST, true);
        if ( ! $this->token) // If login failed, then don't try to execute whatever's next
            return false ;   // Instead, just return false (we will anyway, in the end.
    }
delovelady commented 1 week ago

It looks like Plex may have changed they way a signon request should be organized. The old code:

    if ($isLoginCall) {
        $curlOptArray[CURLOPT_HTTPAUTH] = CURLAUTH_ANY;
        $curlOptArray[CURLOPT_USERPWD]  = $this->username . ':' . $this->password;
    } else {
        $curlOptArray[CURLOPT_HTTPHEADER][] = 'X-Plex-Token: ' . $this->token;
    }

works for me 0% of the time. For me, the following function solves the issue. I have rewritten the building of the curl resource into this function, and now login works for me 100% of the time (when userid and password are valid)

private function createCurlResource(string $path, array $params = [], string $method = self::GET) {

    const PLEX_TV_SIGNIN_URL = 'https://plex.tv/users/sign_in.xml' ;
    ...
    ...
    ...
    $fullURL = $path ;
    if ( ! empty($params))
        $fullURL .= '?' . $this->buildHttpQuery($params) ;
    $resource = curl_init() ;
    $curlOptArray = [
        CURLOPT_URL              => $fullURL
        , CURLOPT_AUTOREFERER    => true                  // suspect
        , CURLOPT_RETURNTRANSFER => true
        , CURLOPT_CONNECTTIMEOUT => $this->timeout        // suspect
        , CURLOPT_TIMEOUT        => $this->timeout        // suspect
        , CURLOPT_FAILONERROR    => true
        , CURLOPT_FOLLOWLOCATION => true                  // suspect
        , CURLOPT_HTTPAUTH       => CURLAUTH_ANY
        , CURLOPT_HTTPHEADER     => [
                                      'X-Plex-Client-Identifier: ' . $this->clientIdentifier
                                    , 'X-Plex-Product: '           . $this->productName
                                    , 'X-Plex-Version: '           . self::VERSION
                                    , 'X-Plex-Device: '            . $this->device
                                    , 'X-Plex-Device-Name: '       . $this->deviceName
                                    , 'X-Plex-Platform: '          . 'Linux'
                                    , 'X-Plex-Platform-Version: '  . self::VERSION
                                    , 'X-Plex-Provides: '          . 'controller'
                                    , 'X-Plex-Username: '          . $this->username
                                        ]
                        ] ;
    if ($fullURL == self::PLEX_TV_SIGNIN_URL) {
        $curlOptArray[CURLOPT_HTTPAUTH] = CURLAUTH_ANY;
        $curlOptArray[CURLOPT_POSTFIELDS] = http_build_query( [ 'user[password]' => $this->password
                                                              , 'user[login]'    => $this->username
                                                                    ]
                                ) ;
    } else {
        $curlOptArray[CURLOPT_HTTPHEADER][] = 'X-Plex-Token: ' . $this->token;
    }
    if ($method == self::POST)
        $curlOptArray['CURLOPT_POST'] = true ;
    elseif ($method != self::GET)
        $curlOptArray['CURLOPT_CUSTOMREQUEST'] = $method ;
    curl_setopt_array($resource, $curlOptArray) ;
    return $resource ;
}