Ayer comentaba sobre la clase PHP para enviar canciones a last.fm. Bueno dado que lo voy a utilizar desde CakePHP lo más lógico era construir un componente, y gracias al HttpSocket de CakePHP el código se redujo bastante. Aquí les dejo el código para usarlo libremente (MIT License)
< ?php
/**
* last.fm component for songs submissions
* Send songs to last.fm using cakephp
*
*
* PHP versions 4 and 5
*
* Copyright 2008, Pablo Viojo
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
* @copyright Copyright 2008, Pablo Viojo (http://pviojo.net)
* @link http://projects.pviojo.net/lastfm
* @version 0.1.1
* @lastmodified 2008-07-26
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*
* Usage sample:
*
if($this->Lastfm->connect($user, $password)){
if(
$this->Lastfm->submit(
array(
'artist'=>'Artist',
'title'=>'Song Name',
'album'=>'Album nane',
'duration'=>duration(secs)
)
)
){
// ...submission success
}
}
*
*/
if (!defined('LASTFM_CONNECTED')){
define ('LASTFM_CONNECTED', 'OK');
}
if (!defined('LASTFM_ERROR')){
define ('LASTFM_ERROR', 'ERROR');
}
App::import('core','HttpSocket');
class LastfmComponent extends Object {
/**
* Constructor.
*/
function startup(&$controller) {
$this->controller = $controller;
$this->clientId = "tst";
$this->clientVer = "1.0";
$this->socket = new HttpSocket();
}
/**
* Connects to lastfm using user and password
*/
function connect($user, $password){
$this->user = $user;
$this->password = $password;
return $this->_handShake();
}
/**
* Returns true if connected to last.fm
*
* @return boolean Connection Status
* @access public
*/
function isConnected(){
if ($this->status==LASTFM_CONNECTED){
return true;
}
return false;
}
/**
* Performs a handshake
*
* @return Status (LASTFM_CONNECTED on success, LASTFM_ERROR otherwise)
* @access private
*/
function _handShake(){
$this->status = false;
$timestamp = time();
$auth = md5(md5($this->password) . $timestamp);
$url = "http://post.audioscrobbler.com/?hs=true&p=1.2.1&c=" . $this->clientId . "&v=" . $this->clientVer . "&u=" . $this->user . "&t=" . $timestamp . "&a=" . $auth ;
$rsp = $this->_execute($url, array('username'=>$this->user, 'password'=>$this->password));
if ($rsp){
$rsp = split("\n",$rsp);
$this->status = $rsp[0];
switch($this->status){
case "OK":
$this->status = LASTFM_CONNECTED;
$this->sessionId = $rsp[1];
$this->urls['nowPlaying'] = $rsp[2];
$this->urls['submission'] = $rsp[3];
break;
default:
$this->status = LASTFM_ERROR;
$this->sessionId = null;
break;
}
}
return $this->status ;
}
/**
* Submit a song to last.fm
* @param array $song array ("artist", "title", "duration", "album"[, "start"] )
* @return boolean Submission Status
* @access public
*/
function submit($song){
$timestamp = time();
$auth = md5(md5($this->password) . $timestamp);
$data = array(
"s"=>$this->sessionId,
"a[0]"=>$song['artist'],
"t[0]"=>$song['title'],
"i[0]"=>(isset($song['start'])?$song['start']:time()),
"o[0]"=>"P",
"r[0]"=>"",
"l[0]"=>$song['duration'],
"b[0]"=>$song['album'],
"n[0]"=>"",
"m[0]"=>""
);
$url = $this->urls['submission'];
$rsp = $this->_execute($url, array('username'=>$this->user, 'password'=>$this->password), 'POST', $data);
switch(trim($rsp)){
case "OK":
return true;
break;
default:
return false;
}
}
/**
* Execute a request
* @access private
*/
function _execute($url, $auth = null, $method = 'GET', $data = null){
$request = array(
'method' => $method,
'uri' => $url
);
if ($auth){
$request = am(
$request,
array(
'auth' => array(
'method' => 'basic',
'user' => $auth["username"],
'pass' => $auth["password"]
)
)
);
}
if (strtoupper($method)=="POST"){
if ($data){
foreach($data as $key=>$value ) {
$postData[$key] = $value;
}
$request['body'] = $postData;
}
}
$output = $this->socket->request($request);
return $output;
}
}

Que tal,
Buen componente y ejemplo de como usar la API de LastFM, aunque tengo una duda.
Porque no pusiste App::import(’core’,'HttpSocket’); al principio, o sea fuera del método _execute(). Y al igual que $socket = new HttpSocket();, no seria mejor ponerlo en startup() onda, $this->httpSocket = new HttpSocket();.
Saludos.
Toda la razón, ya está corregido. Muchas gracias!
Me parece raro usar define() en una clase.
Quizas no habria sido mejor declararlas como atributos privados de una clase?
private $connected = true;
private $error = true;
Asi puedes tener metodos accesadores y modificadores para estas variables y modificarlas cuando estimes. En cambio con define son estaticas.
Ejemplo:
if($lastfm->error()):
$lastfm->setConnected(false);
endif;
if($lastfm->connected == true) {
// Hace lo que tienes que hacer
} else {
return $lastfm->error;
}
@Fabián: El define esta fuera de la clase, y con el tema de declarlas como privadas no estoy muy de acuerdo, ya que connected y error son dos valores posibles para el atributo status, y no atributos de la clase.
En cualquier caso debería declararlas como constantes (const) pero como PHP4 no lo soporta están definidas como están.
Saludos
Pablo es el arte de programar de cada uno