Commit 99e56573796a9566f50902d679b4ff075c79db2e
1 parent
538ca12b
Exists in
master
and in
7 other branches
Implementação de comentários do usuário em uma camada
Showing
90 changed files
with
8682 additions
and
109 deletions
Show diff stats
admin/admin.db
No preview for this file type
admin/index.html
| ... | ... | @@ -181,6 +181,7 @@ essa cria&ccedil;&atilde;o podem ser obtidos no item "Outras op&ccedil;ões".</p> |
| 181 | 181 | <table class=lista1 > |
| 182 | 182 | <tr onclick="abre('html/incluimap.html')"><td><div class=aplicar ></div></td><td>Ajusta mapfiles</td></tr> |
| 183 | 183 | <tr onclick="abre('php/estatisticas.php')"><td><div class=aplicar ></div></td><td>Estatísticas</td></tr> |
| 184 | +<tr onclick="abre('php/upgradebanco44_45.php')"><td><div class=aplicar ></div></td><td>Adiciona as tabelas necessárias à versão 4.5 do i3Geo e que não existiam nas vesões anteriores</td></tr> | |
| 184 | 185 | |
| 185 | 186 | <tr onclick="abre('php/sqlite.php')"><td><div class=aplicar ></div></td><td>Descrição do banco padrão (SQLITE)</td></tr> |
| 186 | 187 | <tr onclick="abre('php/criabanco.php')"><td><div class=aplicar ></div></td><td>Criar banco de dados</td></tr> |
| ... | ... | @@ -191,6 +192,8 @@ essa cria&ccedil;&atilde;o podem ser obtidos no item "Outras op&ccedil;ões".</p> |
| 191 | 192 | <tr onclick="abre('xmlservicosws.php')"><td><div class=aplicar ></div></td><td>Ver xml com a lista de serviços WS (webservices convencionais)</td></tr> |
| 192 | 193 | <tr onclick="abre('xmlsistemas.php')"><td><div class=aplicar ></div></td><td>Ver xml com a lista de sistemas que adicionam temas especiais</td></tr> |
| 193 | 194 | <tr onclick="abre('rssgrupos.php')"><td><div class=aplicar ></div></td><td>Ver RSS com os grupos, subgrupos e temas</td></tr> |
| 195 | +<tr onclick="abre('rsscomentariostemas.php')"><td><div class=aplicar ></div></td><td>Ver RSS com os comentários sobre os temas</td></tr> | |
| 196 | + | |
| 194 | 197 | <tr onclick="abre('hiperbolica.php')"><td><div class=aplicar ></div></td><td>Ver XML para árvorehiperbólica</td></tr> |
| 195 | 198 | </table> |
| 196 | 199 | </div> | ... | ... |
admin/js/editormapfile.js
| ... | ... | @@ -1123,6 +1123,8 @@ function montaEditorMetadados(dados) |
| 1123 | 1123 | titulo:"Aplica extensao (APLICAEXTENSAO)",id:"",value:dados.aplicaextensao,tipo:"text",div:"<div id=cAplicaextensao ></div>"}, |
| 1124 | 1124 | {ajuda:"Indica se o usuário pode abrir o editor de SQL para poder alterar o elemento DATA do Mapfile.", |
| 1125 | 1125 | titulo:"Permite editar SQL (EDITORSQL)",id:"",value:dados.editorsql,tipo:"text",div:"<div id=cEditorsql ></div>"}, |
| 1126 | + {ajuda:"Indica se o usuário pode fazer comentários no tema", | |
| 1127 | + titulo:"Permite comentar (PERMITECOMENTARIO)",id:"",value:dados.permitecomentario,tipo:"text",div:"<div id=cPermitecomentario ></div>"}, | |
| 1126 | 1128 | {ajuda:"Indica se o usuário pode fazer download do tema", |
| 1127 | 1129 | titulo:"Download (DOWNLOAD)",id:"",value:dados.download,tipo:"text",div:"<div id=cDownload ></div>"}, |
| 1128 | 1130 | {ajuda:"Endereço de um arquivo para download dos dados (caminho completo no servidor). Se definido, o sistema irá usar esse arquivo ao invés de gerar os dados, quando o usuário clicar nas opções de download. Se não for definido, o arquivo de download é gerado diretamente do original, convertendo do banco ou copiando o arquivo definido em DATA.", |
| ... | ... | @@ -1203,6 +1205,10 @@ function montaEditorMetadados(dados) |
| 1203 | 1205 | temp += core_combosimnao(dados.editorsql) |
| 1204 | 1206 | temp += "</select>" |
| 1205 | 1207 | $i("cEditorsql").innerHTML = temp |
| 1208 | + temp = "<select id='permitecomentario' >" | |
| 1209 | + temp += core_combosimnao(dados.permitecomentario) | |
| 1210 | + temp += "</select>" | |
| 1211 | + $i("cPermitecomentario").innerHTML = temp | |
| 1206 | 1212 | temp = "<select id='download' >" |
| 1207 | 1213 | temp += core_combosimnao(dados.download) |
| 1208 | 1214 | temp += "</select>" |
| ... | ... | @@ -1563,7 +1569,7 @@ function salvarDadosEditor(tipo,codigoMap,codigoLayer,indiceClasse,indiceEstilo, |
| 1563 | 1569 | else |
| 1564 | 1570 | {alert("Valor de escala incorreto");return;} |
| 1565 | 1571 | } |
| 1566 | - var campos = new Array("cache","iconetema","ltempoformatodata","ltempoiteminicio","ltempoitemfim","ltempoitemtitulo","ltempoitemdescricao","ltempoitemtip","ltempoitemimagem","ltempoitemicone","ltempoitemlink","editorsql","description_template","palletefile","palletestep","arquivodownload","aplicaextensao","classestamanho","classessimbolo","classescor","classesnome","classesitem","mensagem","identifica","extensao","escondido","download","escala","tema","classe","tip","itenslink","itens","itensdesc") | |
| 1572 | + var campos = new Array("permitecomentario","cache","iconetema","ltempoformatodata","ltempoiteminicio","ltempoitemfim","ltempoitemtitulo","ltempoitemdescricao","ltempoitemtip","ltempoitemimagem","ltempoitemicone","ltempoitemlink","editorsql","description_template","palletefile","palletestep","arquivodownload","aplicaextensao","classestamanho","classessimbolo","classescor","classesnome","classesitem","mensagem","identifica","extensao","escondido","download","escala","tema","classe","tip","itenslink","itens","itensdesc") | |
| 1567 | 1573 | var par = "&codigoMap="+codigoMap+"&codigoLayer="+codigoLayer |
| 1568 | 1574 | var prog = "../php/editormapfile.php?funcao=alterarMetadados" |
| 1569 | 1575 | } | ... | ... |
admin/php/classe_arvore.php
| ... | ... | @@ -658,7 +658,6 @@ Verifica se uma string ocorre em um array |
| 658 | 658 | $texto = mb_convert_encoding($texto,mb_detect_encoding($texto),"UTF-8"); |
| 659 | 659 | else |
| 660 | 660 | $texto = mb_convert_encoding($texto,mb_detect_encoding($texto),"ISO-8859-1"); |
| 661 | - | |
| 662 | 661 | return $texto; |
| 663 | 662 | } |
| 664 | 663 | } | ... | ... |
admin/php/conexao.php
| ... | ... | @@ -74,7 +74,7 @@ if($conexaoadmin == "") |
| 74 | 74 | $arquivosqlite = $locaplic."/admin/admin.db"; |
| 75 | 75 | if(!file_exists($arquivosqlite)) |
| 76 | 76 | { |
| 77 | - echo "O arquivo menutemas/admin.db não existe. Utilize i3geo/admin/criabanco.php para criar o banco de dados SQLITE."; | |
| 77 | + echo "O arquivo admin.db não existe. Utilize i3geo/admin/criabanco.php para criar o banco de dados SQLITE."; | |
| 78 | 78 | exit; |
| 79 | 79 | } |
| 80 | 80 | $conAdmin = "sqlite:$arquivosqlite"; | ... | ... |
admin/php/criabanco.php
| ... | ... | @@ -5,7 +5,7 @@ Title: criabanco.php |
| 5 | 5 | Cria um novo banco de dados de administração. |
| 6 | 6 | |
| 7 | 7 | Se vc quiser recriar o banco de dados default, apague o arquivo |
| 8 | -i3geo/menutemas/admin.db ou faça uma cópia. Depois é só executar esse programa. | |
| 8 | +i3geo/admin/admin.db ou faça uma cópia. Depois é só executar esse programa. | |
| 9 | 9 | |
| 10 | 10 | Se a configuração do arquivo de conexão foi alterada (veja ms_configura.php), o novo |
| 11 | 11 | banco irá ser criado conforme a nova string de conexão. |
| ... | ... | @@ -60,15 +60,17 @@ $tabelas = array( |
| 60 | 60 | "CREATE TABLE i3geoadmin_raiz (ordem NUMERIC, id_tema NUMERIC, id_menu NUMERIC, id_nivel NUMERIC, id_raiz INTEGER PRIMARY KEY, nivel NUMERIC, perfil TEXT)", |
| 61 | 61 | "CREATE TABLE i3geoadmin_n1 (publicado TEXT, ordem NUMERIC, id_menu NUMERIC, id_grupo NUMERIC, id_n1 INTEGER PRIMARY KEY, n1_perfil TEXT)", |
| 62 | 62 | "CREATE TABLE i3geoadmin_n2 (publicado TEXT, ordem NUMERIC, id_n1 NUMERIC, id_n2 INTEGER PRIMARY KEY, id_subgrupo NUMERIC, n2_perfil TEXT)", |
| 63 | -"CREATE TABLE i3geoadmin_n3 (publicado TEXT, ordem NUMERIC, id_n2 NUMERIC, id_n3 INTEGER PRIMARY KEY, id_tema NUMERIC, n3_perfil TEXT)" | |
| 63 | +"CREATE TABLE i3geoadmin_n3 (publicado TEXT, ordem NUMERIC, id_n2 NUMERIC, id_n3 INTEGER PRIMARY KEY, id_tema NUMERIC, n3_perfil TEXT)", | |
| 64 | +"CREATE TABLE i3geoadmin_comentarios (comentario TEXT, data TEXT, openidnome TEXT, openidimagem TEXT, openidservico TEXT, openidusuario TEXT, openidurl TEXT, id_tema NUMERIC)" | |
| 65 | + | |
| 64 | 66 | ); |
| 65 | 67 | if($conexaoadmin == "") |
| 66 | 68 | { |
| 67 | - if(file_exists("../../menutemas/admin.db")) | |
| 68 | - {echo "Arquivo menutemas/admin.db ja existe";exit;} | |
| 69 | - $banco = sqlite_open("../../menutemas/admin.db",0666); | |
| 69 | + if(file_exists("../../admin/admin.db")) | |
| 70 | + {echo "Arquivo admin/admin.db ja existe";exit;} | |
| 71 | + $banco = sqlite_open("../../admin/admin.db",0666); | |
| 70 | 72 | $banco = null; |
| 71 | - $dbhw = new PDO('sqlite:../../menutemas/admin.db'); | |
| 73 | + $dbhw = new PDO('sqlite:../../admin/admin.db'); | |
| 72 | 74 | } |
| 73 | 75 | else |
| 74 | 76 | { | ... | ... |
admin/php/editormapfile.php
| ... | ... | @@ -692,6 +692,8 @@ switch (strtoupper($funcao)) |
| 692 | 692 | |
| 693 | 693 | cache |
| 694 | 694 | |
| 695 | + permitecomentario | |
| 696 | + | |
| 695 | 697 | Retorno: |
| 696 | 698 | |
| 697 | 699 | {JSON} |
| ... | ... | @@ -1331,11 +1333,12 @@ function pegaMetadados() |
| 1331 | 1333 | $dados["ltempoitemicone"] = $layer->getmetadata("ltempoitemicone"); |
| 1332 | 1334 | $dados["ltempoitemlink"] = $layer->getmetadata("ltempoitemlink"); |
| 1333 | 1335 | $dados["iconetema"] = $layer->getmetadata("iconetema"); |
| 1336 | + $dados["permitecomentario"] = $layer->getmetadata("permitecomentario"); | |
| 1334 | 1337 | return $dados; |
| 1335 | 1338 | } |
| 1336 | 1339 | function alterarMetadados() |
| 1337 | 1340 | { |
| 1338 | - global $iconetema,$ltempoformatodata,$ltempoiteminicio,$ltempoitemfim,$ltempoitemtitulo,$ltempoitemdescricao,$ltempoitemtip,$ltempoitemimagem,$ltempoitemicone,$ltempoitemlink,$description_template,$palletestep,$palletefile,$arquivodownload,$codigoMap,$codigoLayer,$locaplic,$aplicaextensao,$classestamanho,$classessimbolo,$classescor,$classesnome,$classesitem,$mensagem,$identifica,$extensao,$escondido,$download,$escala,$tema,$classe,$tip,$itenslink,$itens,$itensdesc,$editorsql,$cache; | |
| 1341 | + global $permitecomentario,$iconetema,$ltempoformatodata,$ltempoiteminicio,$ltempoitemfim,$ltempoitemtitulo,$ltempoitemdescricao,$ltempoitemtip,$ltempoitemimagem,$ltempoitemicone,$ltempoitemlink,$description_template,$palletestep,$palletefile,$arquivodownload,$codigoMap,$codigoLayer,$locaplic,$aplicaextensao,$classestamanho,$classessimbolo,$classescor,$classesnome,$classesitem,$mensagem,$identifica,$extensao,$escondido,$download,$escala,$tema,$classe,$tip,$itenslink,$itens,$itensdesc,$editorsql,$cache; | |
| 1339 | 1342 | $dados = array(); |
| 1340 | 1343 | $mapfile = $locaplic."/temas/".$codigoMap.".map"; |
| 1341 | 1344 | $mapa = ms_newMapObj($mapfile); |
| ... | ... | @@ -1375,6 +1378,7 @@ function alterarMetadados() |
| 1375 | 1378 | $layer->setmetadata("ltempoitemicone",$ltempoitemicone); |
| 1376 | 1379 | $layer->setmetadata("ltempoitemlink",$ltempoitemlink); |
| 1377 | 1380 | $layer->setmetadata("iconetema",$iconetema); |
| 1381 | + $layer->setmetadata("permitecomentario",$permitecomentario); | |
| 1378 | 1382 | $mapa->save($mapfile); |
| 1379 | 1383 | removeCabecalho($mapfile); |
| 1380 | 1384 | return "ok"; | ... | ... |
admin/php/sqlite.php
| ... | ... | @@ -32,13 +32,13 @@ Arquivo: |
| 32 | 32 | |
| 33 | 33 | i3geo/admin/php/sqlite.php |
| 34 | 34 | */ |
| 35 | -if(!file_exists("../../menutemas/admin.db")) | |
| 35 | +if(!file_exists("../admin.db")) | |
| 36 | 36 | { |
| 37 | 37 | echo "O arquivo menutemas/admin.db não existe. Utilize i3geo/admin/criasqlite.php para criar o banco de dados SQLITE."; |
| 38 | 38 | exit; |
| 39 | 39 | } |
| 40 | 40 | echo "<pre>"; |
| 41 | -$dbh = new PDO('sqlite:../../menutemas/admin.db'); | |
| 41 | +$dbh = new PDO('sqlite:../admin.db'); | |
| 42 | 42 | echo "<br><br><span style=color:red >Lista de tabelas</span><br><br>"; |
| 43 | 43 | $q = $dbh->query("SELECT name FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type='table' ORDER BY name",PDO::FETCH_ASSOC); |
| 44 | 44 | $resultado = $q->fetchAll(); | ... | ... |
| ... | ... | @@ -0,0 +1,68 @@ |
| 1 | +<?php | |
| 2 | +/* | |
| 3 | +Title: upgradebanco44_45.php | |
| 4 | + | |
| 5 | +Adiciona as novas tabelas utilizadas na versão 4.5 | |
| 6 | + | |
| 7 | +Se vc quiser recriar o banco de dados default, apague o arquivo | |
| 8 | +i3geo/admin/admin.db ou faça uma cópia. Depois é só executar esse programa. | |
| 9 | + | |
| 10 | +Se a configuração do arquivo de conexão foi alterada (veja ms_configura.php), o novo | |
| 11 | +banco irá ser criado conforme a nova string de conexão. | |
| 12 | + | |
| 13 | +Licenca: | |
| 14 | + | |
| 15 | +GPL2 | |
| 16 | + | |
| 17 | +i3Geo Interface Integrada de Ferramentas de Geoprocessamento para Internet | |
| 18 | + | |
| 19 | +Direitos Autorais Reservados (c) 2006 Ministério do Meio Ambiente Brasil | |
| 20 | +Desenvolvedor: Edmar Moretti edmar.moretti@mma.gov.br | |
| 21 | + | |
| 22 | +Este programa é software livre; você pode redistribuí-lo | |
| 23 | +e/ou modificá-lo sob os termos da Licença Pública Geral | |
| 24 | +GNU conforme publicada pela Free Software Foundation; | |
| 25 | + | |
| 26 | +Este programa é distribuído na expectativa de que seja útil, | |
| 27 | +porém, SEM NENHUMA GARANTIA; nem mesmo a garantia implícita | |
| 28 | +de COMERCIABILIDADE OU ADEQUAÇÃO A UMA FINALIDADE ESPECÍFICA. | |
| 29 | +Consulte a Licença Pública Geral do GNU para mais detalhes. | |
| 30 | +Você deve ter recebido uma cópia da Licença Pública Geral do | |
| 31 | +GNU junto com este programa; se não, escreva para a | |
| 32 | +Free Software Foundation, Inc., no endereço | |
| 33 | +59 Temple Street, Suite 330, Boston, MA 02111-1307 USA. | |
| 34 | + | |
| 35 | +Arquivo: | |
| 36 | + | |
| 37 | +i3geo/admin/php/criabanco.php | |
| 38 | +*/ | |
| 39 | +$funcao = ""; | |
| 40 | +include_once("admin.php"); | |
| 41 | +error_reporting(0); | |
| 42 | +if(verificaEditores($editores) == "nao") | |
| 43 | +{echo "Vc nao e um editor cadastrado. Apenas os editores definidos em i3geo/ms_configura.php podem acessar o sistema de administracao.";exit;} | |
| 44 | + | |
| 45 | +$tabelas = array( | |
| 46 | +"CREATE TABLE i3geoadmin_comentarios (comentario TEXT, data TEXT, openidnome TEXT, openidimagem TEXT, openidservico TEXT, openidusuario TEXT, openidurl TEXT, id_tema NUMERIC)" | |
| 47 | +); | |
| 48 | +if($conexaoadmin == "") | |
| 49 | +{ | |
| 50 | + $banco = sqlite_open("../admin.db",0666); | |
| 51 | + $banco = null; | |
| 52 | + $dbhw = new PDO('sqlite:../admin.db'); | |
| 53 | +} | |
| 54 | +else | |
| 55 | +{ | |
| 56 | + include($conexaoadmin); | |
| 57 | +} | |
| 58 | +foreach($tabelas as $tabela) | |
| 59 | +{ | |
| 60 | + if($dbhw->getAttribute(PDO::ATTR_DRIVER_NAME) == "pgsql") | |
| 61 | + { | |
| 62 | + $tabela = str_replace("INTEGER PRIMARY KEY","SERIAL PRIMARY KEY NOT NULL",$tabela); | |
| 63 | + } | |
| 64 | + $q = $dbhw->query($tabela); | |
| 65 | +} | |
| 66 | +$banco = null; | |
| 67 | +echo "Feito!!!"; | |
| 68 | +?> | |
| 0 | 69 | \ No newline at end of file | ... | ... |
admin/php/xml.php
| ... | ... | @@ -92,6 +92,28 @@ function geraXmlSistemas($perfil,$locaplic,$editores) |
| 92 | 92 | return $xml; |
| 93 | 93 | } |
| 94 | 94 | /* |
| 95 | +Function: geraRSScomentariosTemas | |
| 96 | + | |
| 97 | +RSS com os comentarios sobre um ou todos os temas | |
| 98 | + | |
| 99 | +Parametros: | |
| 100 | + | |
| 101 | +locaplic {string} - localização do i3Geo no sistema de arquivos | |
| 102 | + | |
| 103 | +id_tema {numeric} - (opcional) id do tema para mostrar apenas os comentários de um tema | |
| 104 | + | |
| 105 | +Retorno: | |
| 106 | + | |
| 107 | +RSS | |
| 108 | +*/ | |
| 109 | +function geraRSScomentariosTemas($locaplic,$id_tema="") | |
| 110 | +{ | |
| 111 | + $sql = "select b.nome_tema||' '||a.data as nome_ws,a.openidnome||' '||a.openidurl||' &lt;br&gt;'||a.comentario as desc_ws, a.openidnome as autor_ws, b.link_tema as link_ws from i3geoadmin_comentarios as a,i3geoadmin_temas as b where a.id_tema = b.id_tema "; | |
| 112 | + if($id_tema != "") | |
| 113 | + {$sql .= " and a.id_tema = $id_tema ";} | |
| 114 | + return geraXmlRSS($locaplic,$sql,"Lista de comentarios"); | |
| 115 | +} | |
| 116 | +/* | |
| 95 | 117 | Function: geraRSStemas |
| 96 | 118 | |
| 97 | 119 | RSS com os temas cadastrados | ... | ... |
| ... | ... | @@ -0,0 +1,66 @@ |
| 1 | +<?php | |
| 2 | +/* | |
| 3 | +Title: rsscomentariostemas | |
| 4 | + | |
| 5 | +Monta um arquivo XML no padrão RSS contendo os comentários postados para os temas cadastrados. | |
| 6 | + | |
| 7 | +<http://localhost/i3geo/admin/rsscomentariostemas.php> | |
| 8 | + | |
| 9 | +Parametros: | |
| 10 | + | |
| 11 | +id_tema {numeric} - (opcional) id do tema para mostrar apenas os comentários de um tema | |
| 12 | + | |
| 13 | +Licenca: | |
| 14 | + | |
| 15 | +GPL2 | |
| 16 | + | |
| 17 | +i3Geo Interface Integrada de Ferramentas de Geoprocessamento para Internet | |
| 18 | + | |
| 19 | +Direitos Autorais Reservados (c) 2006 Ministério do Meio Ambiente Brasil | |
| 20 | +Desenvolvedor: Edmar Moretti edmar.moretti@mma.gov.br | |
| 21 | + | |
| 22 | +Este programa é software livre; você pode redistribuí-lo | |
| 23 | +e/ou modificá-lo sob os termos da Licença Pública Geral | |
| 24 | +GNU conforme publicada pela Free Software Foundation; | |
| 25 | + | |
| 26 | +Este programa é distribuído na expectativa de que seja útil, | |
| 27 | +porém, SEM NENHUMA GARANTIA; nem mesmo a garantia implícita | |
| 28 | +de COMERCIABILIDADE OU ADEQUAÇÃO A UMA FINALIDADE ESPECÍFICA. | |
| 29 | +Consulte a Licença Pública Geral do GNU para mais detalhes. | |
| 30 | +Você deve ter recebido uma cópia da Licença Pública Geral do | |
| 31 | +GNU junto com este programa; se não, escreva para a | |
| 32 | +Free Software Foundation, Inc., no endereço | |
| 33 | +59 Temple Street, Suite 330, Boston, MA 02111-1307 USA. | |
| 34 | + | |
| 35 | +Arquivo: | |
| 36 | + | |
| 37 | +i3geo/admin/rsscomentariostemas.php | |
| 38 | +*/ | |
| 39 | + | |
| 40 | +error_reporting(0); | |
| 41 | +if(!isset($locaplic)) | |
| 42 | +{ | |
| 43 | + $locaplic = ""; | |
| 44 | + if(file_exists("../../../ms_configura.php")) | |
| 45 | + {include_once("../../../ms_configura.php");} | |
| 46 | + else | |
| 47 | + { | |
| 48 | + if(file_exists("../../ms_configura.php")) | |
| 49 | + {include_once("../../ms_configura.php");} | |
| 50 | + else | |
| 51 | + { | |
| 52 | + if(file_exists("../ms_configura.php")) | |
| 53 | + {include_once("../ms_configura.php");} | |
| 54 | + else | |
| 55 | + include_once("ms_configura.php"); | |
| 56 | + } | |
| 57 | + } | |
| 58 | +} | |
| 59 | +include_once($locaplic."/classesphp/pega_variaveis.php"); | |
| 60 | +include_once($locaplic."/admin/php/xml.php"); | |
| 61 | +$parametros = array_merge($_POST,$_GET); | |
| 62 | +if(empty($parametros["id_tema"])) | |
| 63 | +{$parametros["id_tema"] = "";} | |
| 64 | +echo header("Content-type: application/xml"); | |
| 65 | +echo geraRSScomentariosTemas($locaplic,$parametros["id_tema"]); | |
| 66 | +?> | ... | ... |
admin/rsstemas.php
classesjs/classe_arvoredecamadas.js
| ... | ... | @@ -246,8 +246,7 @@ i3GEO.arvoreDeCamadas = { |
| 246 | 246 | |
| 247 | 247 | "editorsql":"sim", |
| 248 | 248 | |
| 249 | - "iconetema":"" | |
| 250 | - | |
| 249 | + "iconetema":"" | |
| 251 | 250 | } |
| 252 | 251 | ] |
| 253 | 252 | |
| ... | ... | @@ -779,6 +778,9 @@ i3GEO.arvoreDeCamadas = { |
| 779 | 778 | //i3GEO.arvoreDeCamadas.adicionaOpcaoTema($trad("t43"),$trad("t43"),'i3GEO.tema.dialogo.aplicarsld(\"'+ltema.name+'\")',node); |
| 780 | 779 | if(ltema.editorsql == "sim" || ltema.editorsql == "SIM") |
| 781 | 780 | {i3GEO.arvoreDeCamadas.adicionaOpcaoTema($trad("t40"),$trad("t41"),'i3GEO.tema.dialogo.editorsql(\"'+ltema.name+'\")',node);} |
| 781 | + if(ltema.permitecomentario.toLowerCase() !== "nao") | |
| 782 | + {i3GEO.arvoreDeCamadas.adicionaOpcaoTema($trad("t45"),$trad("t45"),'i3GEO.tema.dialogo.comentario(\"'+ltema.name+'\")',node);} | |
| 783 | + | |
| 782 | 784 | if(i3GEO.arvoreDeTemas.OPCOESADICIONAIS.navegacaoDir == true) |
| 783 | 785 | {i3GEO.arvoreDeCamadas.adicionaOpcaoTema($trad("t44"),"<span style=color:red >"+$trad("t44")+"</span>",'i3GEO.tema.dialogo.salvaMapfile(\"'+ltema.name+'\")',node);} |
| 784 | 786 | node.loadComplete(); | ... | ... |
classesjs/classe_arvoredetemas.js
| ... | ... | @@ -83,7 +83,9 @@ i3GEO.arvoreDeTemas = { |
| 83 | 83 | |
| 84 | 84 | carousel: true, |
| 85 | 85 | |
| 86 | - uploadgpx: true | |
| 86 | + uploadgpx: true, | |
| 87 | + | |
| 88 | + comentarios: true | |
| 87 | 89 | } |
| 88 | 90 | |
| 89 | 91 | Tipo: |
| ... | ... | @@ -108,7 +110,8 @@ i3GEO.arvoreDeTemas = { |
| 108 | 110 | estrelas: true, |
| 109 | 111 | refresh: true, |
| 110 | 112 | carousel: true, |
| 111 | - uploadgpx: true | |
| 113 | + uploadgpx: true, | |
| 114 | + comentarios: true | |
| 112 | 115 | }, |
| 113 | 116 | /* |
| 114 | 117 | Propriedade: FATORESTRELA |
| ... | ... | @@ -976,7 +979,8 @@ i3GEO.arvoreDeTemas = { |
| 976 | 979 | idtema:raiz[i].tid, |
| 977 | 980 | fonte:raiz[i].link, |
| 978 | 981 | ogc:raiz[i].ogc, |
| 979 | - kmz:raiz[i].kmz | |
| 982 | + kmz:raiz[i].kmz, | |
| 983 | + permitecomentario:raiz[i].permitecomentario | |
| 980 | 984 | }, |
| 981 | 985 | node, |
| 982 | 986 | false, |
| ... | ... | @@ -1209,6 +1213,17 @@ i3GEO.arvoreDeTemas = { |
| 1209 | 1213 | tempNode.enableHighlight = false; |
| 1210 | 1214 | tempNode.isLeaf = true; |
| 1211 | 1215 | } |
| 1216 | + if (node.data.permitecomentario != "nao" && i3GEO.arvoreDeTemas.OPCOESADICIONAIS.comentarios === true){ | |
| 1217 | + html = "<a href='#' title='' onclick='i3GEO.tema.dialogo.comentario(\""+node.data.idtema+"\",\"comentario\")' >Comentário</a>"; | |
| 1218 | + tempNode = new YAHOO.widget.HTMLNode( | |
| 1219 | + {html:html}, | |
| 1220 | + node, | |
| 1221 | + false, | |
| 1222 | + true | |
| 1223 | + ); | |
| 1224 | + tempNode.enableHighlight = false; | |
| 1225 | + tempNode.isLeaf = true; | |
| 1226 | + } | |
| 1212 | 1227 | if(i3GEO.arvoreDeTemas.OPCOESADICIONAIS.qrcode === true){ |
| 1213 | 1228 | lkgrcode = i3GEO.arvoreDeTemas.LOCAPLIC+"/pacotes/qrcode/php/qr_html.php?d="+i3GEO.arvoreDeTemas.LOCAPLIC+"/mobile/index.php?temasa="+node.data.idtema; |
| 1214 | 1229 | lkgrcode1 = i3GEO.arvoreDeTemas.LOCAPLIC+"/pacotes/qrcode/php/qr_img.php?d="+i3GEO.arvoreDeTemas.LOCAPLIC+"/mobile/index.php?temasa="+node.data.idtema; | ... | ... |
classesjs/classe_barradebotoes.js
| ... | ... | @@ -510,6 +510,8 @@ i3GEO.barraDeBotoes = { |
| 510 | 510 | */ |
| 511 | 511 | inicializaBarra:function(idconteudo,idconteudonovo,barraZoom,x,y,onde){ |
| 512 | 512 | if(typeof(console) !== 'undefined'){console.info("i3GEO.barraDeBotoes.inicializaBarra()");} |
| 513 | + if(i3GEO.util.pegaCookie("botoesAjuda") == "nao") | |
| 514 | + {i3GEO.barraDeBotoes.AJUDA = false;} | |
| 513 | 515 | if(i3GEO.barraDeBotoes.TEMPLATEBOTAO === "") |
| 514 | 516 | {i3GEO.barraDeBotoes.TEMPLATEBOTAO = "<div style='display:inline;background-color:rgb(250,250,250);'><p style='font-size:2px;'> </p><img style='border:0px solid white;' src='"+i3GEO.configura.locaplic+"/imagens/branco.gif' id='$$'/></div>";} |
| 515 | 517 | var tipo,mostra,numerobotoes = 0,i,temp,elementos,nelementos = 0,e,wj,recuo,novoel,alturadisponivel,n,chaves,re,estilo; |
| ... | ... | @@ -908,10 +910,9 @@ i3GEO.barraDeBotoes = { |
| 908 | 910 | else |
| 909 | 911 | {document.body.appendChild(divmensagem);} |
| 910 | 912 | if(i3GEO.barraDeBotoes.TIPOAJUDA == "horizontal") |
| 911 | - {divmensagem.innerHTML = "<table style='z-index:20000' ><tr><td id='imgMensagemBarraDeBotoes' style='background:none;padding-top:2px;padding-right:3px;vertical-align:top'><img src='"+$im("left.png")+"' ></td><td style='text-align:left;border-left:1px solid rgb(210,210,210)'><span style='text-align:right;cursor:pointer;color:blue;' onclick='javascript:i3GEO.barraDeBotoes.AJUDA = false;'>fecha</span><br><div style='vertical-align:middle;text-align:left;width:250px;border: 0px solid black;border-left:1px;' id='divMensagemBarraDeBotoesCorpo'></div></td></tr></table>";} | |
| 913 | + {divmensagem.innerHTML = "<table style='z-index:20000' ><tr><td id='imgMensagemBarraDeBotoes' style='background:none;padding-top:2px;padding-right:3px;vertical-align:top'><img src='"+$im("left.png")+"' ></td><td style='text-align:left;border-left:1px solid rgb(210,210,210)'><span style='text-align:right;cursor:pointer;color:blue;' onclick='javascript:i3GEO.util.insereCookie(\"botoesAjuda\",\"nao\");i3GEO.barraDeBotoes.AJUDA = false;'>fecha</span><br><div style='vertical-align:middle;text-align:left;width:250px;border: 0px solid black;border-left:1px;' id='divMensagemBarraDeBotoesCorpo'></div></td></tr></table>";} | |
| 912 | 914 | if(i3GEO.barraDeBotoes.TIPOAJUDA == "vertical") |
| 913 | - {divmensagem.innerHTML = "<table style='z-index:20000' ><tr><td id='imgMensagemBarraDeBotoes' style='background:none;padding-top:2px;padding-right:3px;vertical-align:top'><img src='"+$im("top.png")+"' ></td><td style='text-align:left;border-left:1px solid rgb(210,210,210)'><span style='text-align:right;cursor:pointer;color:blue;' onclick='javascript:i3GEO.barraDeBotoes.AJUDA = false;'>fecha</span><br><div style='vertical-align:middle;text-align:left;width:250px;border: 0px solid black;border-left:1px;' id='divMensagemBarraDeBotoesCorpo'></div></td></tr></table>";} | |
| 914 | - | |
| 915 | + {divmensagem.innerHTML = "<table style='z-index:20000' ><tr><td id='imgMensagemBarraDeBotoes' style='background:none;padding-top:2px;padding-right:3px;vertical-align:top'><img src='"+$im("top.png")+"' ></td><td style='text-align:left;border-left:1px solid rgb(210,210,210)'><span style='text-align:right;cursor:pointer;color:blue;' onclick='javascript:i3GEO.util.insereCookie(\"botoesAjuda\",\"nao\");i3GEO.barraDeBotoes.AJUDA = false;'>fecha</span><br><div style='vertical-align:middle;text-align:left;width:250px;border: 0px solid black;border-left:1px;' id='divMensagemBarraDeBotoesCorpo'></div></td></tr></table>";} | |
| 915 | 916 | } |
| 916 | 917 | if(mensagem != ""){ |
| 917 | 918 | if(i3GEO.barraDeBotoes.TIPOAJUDA == "horizontal"){ | ... | ... |
classesjs/classe_i3geo.js
| ... | ... | @@ -114,6 +114,8 @@ i3GEO = { |
| 114 | 114 | embedLegenda {String} - sim|nao indica se na inicialização a legenda foi inserida no conteúdo do mapa ou não |
| 115 | 115 | |
| 116 | 116 | celularef {Numeric} - tamanho da célula do mapa de referência |
| 117 | + | |
| 118 | + autenticadoopenid {sim|nao} - indica se o usuário foi autenticado em alguma rede social | |
| 117 | 119 | */ |
| 118 | 120 | parametros: { |
| 119 | 121 | mapexten: "", |
| ... | ... | @@ -141,7 +143,8 @@ i3GEO = { |
| 141 | 143 | mensageminicia:"", |
| 142 | 144 | interfacePadrao:"geral.htm", |
| 143 | 145 | embedLegenda:"nao", |
| 144 | - celularef:"" | |
| 146 | + celularef:"", | |
| 147 | + autenticadoopenid:"nao" | |
| 145 | 148 | }, |
| 146 | 149 | /* |
| 147 | 150 | Propriedade: finaliza |
| ... | ... | @@ -224,37 +227,6 @@ i3GEO = { |
| 224 | 227 | // |
| 225 | 228 | tamanho = i3GEO.calculaTamanho(); |
| 226 | 229 | i3GEO.Interface.cria(tamanho[0],tamanho[1]); |
| 227 | - | |
| 228 | - /* | |
| 229 | - i3GEO.parametros = { | |
| 230 | - mapexten: "", | |
| 231 | - mapscale: "", | |
| 232 | - mapres: "", | |
| 233 | - pixelsize: "", | |
| 234 | - mapfile: "", | |
| 235 | - cgi: "", | |
| 236 | - extentTotal: "", | |
| 237 | - mapimagem: "", | |
| 238 | - geoip: "", | |
| 239 | - listavisual: "", | |
| 240 | - utilizacgi:"", | |
| 241 | - versaoms:"", | |
| 242 | - versaomscompleta:"", | |
| 243 | - mensagens:"", | |
| 244 | - w: tamanho[0], | |
| 245 | - h: tamanho[1], | |
| 246 | - locsistemas:"", | |
| 247 | - locidentifica:"", | |
| 248 | - r:"", | |
| 249 | - locmapas:"", | |
| 250 | - extentref:"", | |
| 251 | - kmlurl:"", | |
| 252 | - mensageminicia:"", | |
| 253 | - interfacePadrao:"geral.htm", | |
| 254 | - embedLegenda:"nao", | |
| 255 | - celularef: "" | |
| 256 | - }; | |
| 257 | - */ | |
| 258 | 230 | if(tamanho[0] < 550){ |
| 259 | 231 | i = $i(i3GEO.gadgets.PARAMETROS.mostraQuadros.idhtml); |
| 260 | 232 | if(i){i.style.display = "none";} |
| ... | ... | @@ -295,57 +267,12 @@ i3GEO = { |
| 295 | 267 | } |
| 296 | 268 | else{ |
| 297 | 269 | if(retorno.data.variaveis){ |
| 298 | - // | |
| 299 | - //executa com eval a string que é retornada pelo servidor (função inicia do mapa_controle.php | |
| 300 | - // | |
| 301 | - | |
| 302 | - /* | |
| 303 | - tempo = ""; | |
| 304 | - titulo = ""; | |
| 305 | - eval(retorno.data.variaveis); | |
| 306 | - try{ | |
| 307 | - if (titulo !== "") | |
| 308 | - {top.document.title = titulo;} | |
| 309 | - } | |
| 310 | - catch(e){} | |
| 311 | - i3GEO.ajuda.mostraJanela("Tempo de desenho em segundos: "+tempo,""); | |
| 312 | - | |
| 313 | - try{ | |
| 314 | - i3GEO.parametros.mapexten= mapexten; | |
| 315 | - i3GEO.parametros.mapscale= parseInt(mapscale,10); | |
| 316 | - i3GEO.parametros.mapres= mapres; | |
| 317 | - i3GEO.parametros.pixelsize= g_celula; | |
| 318 | - i3GEO.parametros.mapfile= mapfile; | |
| 319 | - i3GEO.parametros.cgi= cgi; | |
| 320 | - i3GEO.parametros.extentTotal=mapexten; | |
| 321 | - i3GEO.parametros.mapimagem= mapimagem; | |
| 322 | - i3GEO.parametros.geoip= geoip; | |
| 323 | - i3GEO.parametros.listavisual= listavisual; | |
| 324 | - i3GEO.parametros.utilizacgi= utilizacgi; | |
| 325 | - i3GEO.parametros.versaoms= versaoms; | |
| 326 | - i3GEO.parametros.mensagens= mensagens; | |
| 327 | - i3GEO.parametros.locsistemas = locsistemas; | |
| 328 | - i3GEO.parametros.locidentifica = locidentifica; | |
| 329 | - i3GEO.parametros.r = r; | |
| 330 | - i3GEO.parametros.locmapas = locmapas; | |
| 331 | - i3GEO.parametros.extentref = extentref; | |
| 332 | - i3GEO.parametros.versaoms = versaoms; | |
| 333 | - i3GEO.parametros.versaomscompleta = versaomscompleta; | |
| 334 | - i3GEO.parametros.kmlurl = kmlurl; | |
| 335 | - i3GEO.parametros.mensageminicia = mensagemInicia; | |
| 336 | - i3GEO.parametros.interfacePadrao = interfacePadrao; | |
| 337 | - i3GEO.parametros.embedLegenda = embedLegenda; | |
| 338 | - } | |
| 339 | - catch(e){alert("Erro durante a definicao de i3GEO.parametros "+e);} | |
| 340 | - */ | |
| 341 | 270 | i3GEO.parametros = retorno.data.variaveis; |
| 342 | - | |
| 343 | 271 | i3GEO.parametros.mapscale = i3GEO.parametros.mapscale*1; |
| 344 | 272 | i3GEO.parametros.mapres = i3GEO.parametros.mapres*1; |
| 345 | 273 | i3GEO.parametros.pixelsize = i3GEO.parametros.pixelsize*1; |
| 346 | 274 | i3GEO.parametros.w = i3GEO.parametros.w*1; |
| 347 | 275 | i3GEO.parametros.h = i3GEO.parametros.h*1; |
| 348 | - | |
| 349 | 276 | i3GEO.arvoreDeCamadas.CAMADAS = retorno.data.temas; |
| 350 | 277 | if(retorno.data.variaveis.navegacaoDir == "sim") |
| 351 | 278 | {i3GEO.arvoreDeTemas.OPCOESADICIONAIS.navegacaoDir = true;} |
| ... | ... | @@ -389,8 +316,6 @@ i3GEO = { |
| 389 | 316 | if (!$i("i3geo")) |
| 390 | 317 | {document.body.id = "i3geo";} |
| 391 | 318 | $i("i3geo").className = "yui-skin-sam"; |
| 392 | - //if($i("mst")) | |
| 393 | - //{$i("mst").style.visibility ="hidden";} | |
| 394 | 319 | // |
| 395 | 320 | //se i3GEO.configura.sid = "", o html foi aberto diretamente |
| 396 | 321 | //então, é necessário criar os arquivos temporários do mapa | ... | ... |
classesjs/classe_tema.js
| ... | ... | @@ -350,6 +350,18 @@ i3GEO.tema = { |
| 350 | 350 | */ |
| 351 | 351 | dialogo:{ |
| 352 | 352 | /* |
| 353 | + Function: comentario | |
| 354 | + | |
| 355 | + Abre a janela de diálogo para o usuário ver e inserir comentarios em um tema | |
| 356 | + | |
| 357 | + Parametros: | |
| 358 | + | |
| 359 | + tema - código do tema escolhido | |
| 360 | + */ | |
| 361 | + comentario: function(tema){ | |
| 362 | + i3GEO.janela.cria("530px","330px",i3GEO.configura.locaplic+"/ferramentas/comentarios/index.php?tema="+tema+"&g_sid="+i3GEO.configura.sid+"&locaplic="+i3GEO.configura.locaplic,"","","<img src='"+i3GEO.configura.locaplic+"/imagens/player_volta.png' style=cursor:pointer onclick='javascript:history.go(-1)'><span style=position:relative;top:-2px; > Comentários de "+tema+" </span><a class=ajuda_usuario target=_blank href='"+i3GEO.configura.locaplic+"/ajuda_usuario.php?idcategoria=7&idajuda=68' > </a>","comentario"+Math.random()); | |
| 363 | + }, | |
| 364 | + /* | |
| 353 | 365 | Function: cortina |
| 354 | 366 | |
| 355 | 367 | Abre a janela de diálogo da ferramenta cortina | ... | ... |
classesjs/dicionario.js
classesjs/dicionario_ajuda.js
| ... | ... | @@ -786,6 +786,14 @@ g_traducao_ajuda = { |
| 786 | 786 | pt:"Salva as definições da camada no arquivo mapfile de origem", |
| 787 | 787 | complemento:"Essa opção só é ativada para usuários que são administradores. Permite que a camada seja alterada, por exemplo, modificando-se a legenda, e que o resultado seja salvo nas definições originais da camada.", |
| 788 | 788 | apijs:"i3GEO.tema.dialogo.salvaMapfile()" |
| 789 | + }, | |
| 790 | + "93": { | |
| 791 | + titulo: "Comentários", | |
| 792 | + diretorio:"i3geo/ferramentas/comentarios", | |
| 793 | + categoria:"5", | |
| 794 | + pt:"Mostra os comentários existentes sobre o tema e permite ao usuário inserir novos", | |
| 795 | + complemento:"Para entar com um comentário, o usuário precisa ser autenticado em alguma das redes sociais compatíveis com a rotina de login disponível no i3Geo", | |
| 796 | + apijs:"i3GEO.tema.dialogo.comentario()" | |
| 789 | 797 | } |
| 790 | 798 | } |
| 791 | 799 | }; | ... | ... |
classesphp/classe_mapa.php
| ... | ... | @@ -221,6 +221,9 @@ string - javascript com os parametros |
| 221 | 221 | $ltempo = "nao"; |
| 222 | 222 | if($oLayer->getmetadata("ltempoformatodata") !== "") |
| 223 | 223 | {$ltempo = "sim";} |
| 224 | + $permitecomentario = "nao"; | |
| 225 | + if($oLayer->getmetadata("nomeoriginal") != "" && strtoupper($oLayer->getmetadata("pemitecomentario")) != "NAO") | |
| 226 | + {$permitecomentario = "sim";} | |
| 224 | 227 | $temas[] = array( |
| 225 | 228 | "name"=>($oLayer->name), |
| 226 | 229 | "status"=>($oLayer->status), |
| ... | ... | @@ -240,7 +243,8 @@ string - javascript com os parametros |
| 240 | 243 | "linhadotempo"=>$ltempo, |
| 241 | 244 | "escondido"=>strtolower($escondido), |
| 242 | 245 | "iconetema"=>($oLayer->getmetadata("iconetema")), |
| 243 | - "classe"=>($oLayer->getmetadata("classe")) | |
| 246 | + "classe"=>($oLayer->getmetadata("classe")), | |
| 247 | + "permitecomentario"=>$permitecomentario | |
| 244 | 248 | ); |
| 245 | 249 | } |
| 246 | 250 | } | ... | ... |
classesphp/mapa_controle.php
| ... | ... | @@ -124,11 +124,11 @@ if ($funcao != "criaMapa") |
| 124 | 124 | eval("\$".$k."='".$_SESSION[$k]."';"); |
| 125 | 125 | } |
| 126 | 126 | $postgis_mapa = $_SESSION["postgis_mapa"]; |
| 127 | - if(isset($fingerprint)) | |
| 128 | - { | |
| 127 | + //if(isset($fingerprint)) | |
| 128 | + //{ | |
| 129 | 129 | if (md5('I3GEOSEC' . $_SERVER['HTTP_USER_AGENT'] . session_id()) != $fingerprint) |
| 130 | 130 | {exit;} |
| 131 | - } | |
| 131 | + //} | |
| 132 | 132 | } |
| 133 | 133 | // |
| 134 | 134 | //verifica se deve ativar o debug |
| ... | ... | @@ -2929,7 +2929,7 @@ function redesenhaMapa() |
| 2929 | 2929 | $m->salva(); |
| 2930 | 2930 | } |
| 2931 | 2931 | include_once("classe_mapa.php"); |
| 2932 | - $m = New Mapa($map_file); | |
| 2932 | + $m = New Mapa($map_file,$locaplic); | |
| 2933 | 2933 | $par = $m->parametrosTemas(); |
| 2934 | 2934 | // |
| 2935 | 2935 | //na interface googlemaps não é necessário gerar a imagem | ... | ... |
classesphp/mapa_inicia.php
| ... | ... | @@ -42,6 +42,8 @@ Inicia um mapa e obtém os parâmetros necessários para o funcionamento da interfa |
| 42 | 42 | |
| 43 | 43 | Globais: |
| 44 | 44 | |
| 45 | +$openid - indica se o usuário foi ou não autenticado em alguma rede social (veja i3geo/pacotes/openid) | |
| 46 | + | |
| 45 | 47 | $interfacePadrao - interface definida em ms_configura.php |
| 46 | 48 | |
| 47 | 49 | $navegadoresLocais - array que indica quais usuários podem navegar no servidor |
| ... | ... | @@ -96,7 +98,7 @@ Retorno: |
| 96 | 98 | */ |
| 97 | 99 | function iniciaMapa() |
| 98 | 100 | { |
| 99 | - global $interfacePadrao,$mensagemInicia,$kmlurl,$tituloInstituicao,$tempo,$navegadoresLocais,$locaplic,$embedLegenda,$map_file,$mapext,$w,$h,$R_path,$locmapserv,$utilizacgi,$expoeMapfile,$interface; | |
| 101 | + global $openid,$interfacePadrao,$mensagemInicia,$kmlurl,$tituloInstituicao,$tempo,$navegadoresLocais,$locaplic,$embedLegenda,$map_file,$mapext,$w,$h,$R_path,$locmapserv,$utilizacgi,$expoeMapfile,$interface; | |
| 100 | 102 | if(!isset($kmlurl)) |
| 101 | 103 | {$kmlurl = "";} |
| 102 | 104 | error_reporting(E_ALL); |
| ... | ... | @@ -195,7 +197,7 @@ function iniciaMapa() |
| 195 | 197 | // |
| 196 | 198 | $qyfile = str_replace(".map",".qy",$map_file); |
| 197 | 199 | $arqsel = (file_exists($qyfile)) ? true : false; |
| 198 | - $m = New Mapa($map_file); | |
| 200 | + $m = New Mapa($map_file,$locaplic); | |
| 199 | 201 | $temas = $m->parametrosTemas(); |
| 200 | 202 | //$m->ligaDesligaTemas("",implode(",",$m->nomes),"nao"); |
| 201 | 203 | // |
| ... | ... | @@ -264,6 +266,10 @@ function iniciaMapa() |
| 264 | 266 | $res["mappath"] = $imgo->imagepath; |
| 265 | 267 | $res["mapurl"] = $imgo->imageurl; |
| 266 | 268 | $res["navegacaoDir"] = $navegadoresLocais; |
| 269 | + if($openid == true) | |
| 270 | + {$res["autenticadoopenid"] = "sim";} | |
| 271 | + else | |
| 272 | + {$res["autenticadoopenid"] = "nao";} | |
| 267 | 273 | |
| 268 | 274 | copy($map_file,(str_replace(".map","reinc.map",$map_file))); |
| 269 | 275 | copy($map_file,(str_replace(".map","seguranca.map",$map_file))); | ... | ... |
| ... | ... | @@ -0,0 +1,112 @@ |
| 1 | +<html> | |
| 2 | +<head> | |
| 3 | +<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1"> | |
| 4 | +<link rel="stylesheet" type="text/css" href="../../admin/html/admin.css"> | |
| 5 | +</head> | |
| 6 | +<body> | |
| 7 | +<?php | |
| 8 | +/* | |
| 9 | +Parametros: | |
| 10 | + | |
| 11 | +g_sid | |
| 12 | + | |
| 13 | +tema - tema que será comentado | |
| 14 | +*/ | |
| 15 | +$parametrosURL = array_merge($_GET,$_POST); | |
| 16 | + | |
| 17 | +session_name("openid"); | |
| 18 | +session_start(); | |
| 19 | +if(!empty($parametrosURL["limpalogin"])) | |
| 20 | +{ | |
| 21 | + session_destroy(); | |
| 22 | + session_name("openid"); | |
| 23 | + session_start(); | |
| 24 | + $_SESSION["g_sid"] = $parametrosURL["g_sid"]; | |
| 25 | +} | |
| 26 | +if(!empty($parametrosURL["tema"])) | |
| 27 | +{$_SESSION["tema"] = $parametrosURL["tema"];} | |
| 28 | +if(!empty($parametrosURL["locaplic"])) | |
| 29 | +{$_SESSION["locaplic"] = $parametrosURL["locaplic"];} | |
| 30 | +$_SESSION["urlVolta"] = $_SESSION["locaplic"]."/ferramentas/comentarios/index.php"; | |
| 31 | + | |
| 32 | + | |
| 33 | +if($_SESSION["openid"] == true && $_POST["novocomentario"] != "") | |
| 34 | +{gravaComentario();} | |
| 35 | + | |
| 36 | +listaComentarios($_SESSION["tema"]); | |
| 37 | + | |
| 38 | +if($_SESSION["openid"] == true) | |
| 39 | +{formularioInsere();} | |
| 40 | +else | |
| 41 | +{linkOpenid();} | |
| 42 | + | |
| 43 | +function linkOpenId() | |
| 44 | +{ | |
| 45 | + $urlVolta = $_SESSION["locaplic"]."/ferramentas/comentarios/index.php?"; | |
| 46 | + $urlVolta .= "tema=".$_SESSION["tema"]; | |
| 47 | + $url = $_SESSION["locaplic"]."/pacotes/openid/login.php?"; | |
| 48 | + echo "<p><a href='".$url."' target=_self ><img style='border:0px solid white' src='../../imagens/plus.png' >Inserir comentário</a>"; | |
| 49 | +} | |
| 50 | +function formularioInsere() | |
| 51 | +{ | |
| 52 | + echo "<p>Adicione um comentário:</p>"; | |
| 53 | + $url = $_SESSION["locaplic"]."/ferramentas/comentarios/index.php?g_sid=".$_SESSION["g_sid"]."&tema=".$_SESSION["tema"]; | |
| 54 | + echo "<form action='".$url."' method='post'>"; | |
| 55 | + echo " <textarea name=novocomentario value='' type='text' style='height:150px;width:98%' ></textarea><br>"; | |
| 56 | + echo " <input type=submit value='Salvar' />"; | |
| 57 | + echo "</form>"; | |
| 58 | + echo "<p>Para alterar o seu login e escolher uma outra rede, <a href='".$url."&limpalogin=sim' >clique aqui</a>"; | |
| 59 | +} | |
| 60 | +function listaComentarios() | |
| 61 | +{ | |
| 62 | + $locaplic = "../.."; | |
| 63 | + include("../../admin/php/conexao.php"); | |
| 64 | + $data = gmdate("d-m-Y\TH:i:s\Z"); | |
| 65 | + $id_tema = $dbh->query("select * from i3geoadmin_temas where codigo_tema = '".$_SESSION["tema"]."' ",PDO::FETCH_ASSOC); | |
| 66 | + $id_tema = $id_tema->fetchAll(); | |
| 67 | + $id_tema = $id_tema[0]["id_tema"]; | |
| 68 | + $lista = $dbh->query("select * from i3geoadmin_comentarios where id_tema = $id_tema ",PDO::FETCH_ASSOC); | |
| 69 | + $lista = $lista->fetchAll(); | |
| 70 | + echo "<p><a href='../../admin/rsscomentariostemas.php'><img src='../../imagens/rss.gif' style='border:0px solid gray;' > todos os comentários</a>"; | |
| 71 | + echo " <a href='../../admin/rsscomentariostemas.php?id_tema=".$id_tema."'><img src='../../imagens/rss.gif' style='border:0px solid gray;' > comentários para o tema</a></p>"; | |
| 72 | + | |
| 73 | + echo "<table>"; | |
| 74 | + foreach ($lista as $reg) | |
| 75 | + { | |
| 76 | + //echo "<tr><td> </td><td></td></tr><tr>"; | |
| 77 | + echo "<td style='vertical-align:top;border-top:2px solid white;' >"; | |
| 78 | + if($reg["openidimagem"] != "") | |
| 79 | + {echo "<img src='".$reg["openidimagem"]."'/> ";} | |
| 80 | + echo "<p><a href='".$reg["openidurl"]."'>".$reg["openidnome"]."</a></td>"; | |
| 81 | + echo "<td style='vertical-align:top;border-top:2px solid white;' ><p style=line-height:15px ><span style=color:gray >".$reg["data"]."</span><br>".mb_convert_encoding($reg["comentario"],"ISO-8859-1",mb_detect_encoding($reg["comentario"]))."<br></td>"; | |
| 82 | + echo "</tr>"; | |
| 83 | + } | |
| 84 | + echo "</table><hr>"; | |
| 85 | + $dbhw = null; | |
| 86 | + $dbh = null; | |
| 87 | +} | |
| 88 | +function gravaComentario() | |
| 89 | +{ | |
| 90 | + //necessário para os includes do admin.php | |
| 91 | + include_once("../../admin/php/conexao.php"); | |
| 92 | + $data = gmdate("d-m-Y\TH:i:s\Z"); | |
| 93 | + $id_tema = $dbh->query("select * from i3geoadmin_temas where codigo_tema = '".$_SESSION["tema"]."' ",PDO::FETCH_ASSOC); | |
| 94 | + $id_tema = $id_tema->fetchAll(); | |
| 95 | + $id_tema = $id_tema[0]["id_tema"]; | |
| 96 | + $q = "INSERT INTO i3geoadmin_comentarios (comentario,data,openidnome,openidimagem,openidservico,openidusuario,openidurl,id_tema) VALUES ('".converte($_POST["novocomentario"])."','".$data."','".$_SESSION["openidnome"]."','".$_SESSION["openidimagem"]."','".$_SESSION["openidservico"]."','".$_SESSION["openidusuario"]."','".$_SESSION["openidurl"]."','".$id_tema."')"; | |
| 97 | + $dbhw->query($q); | |
| 98 | + $dbhw = null; | |
| 99 | + $dbh = null; | |
| 100 | +} | |
| 101 | +function converte($texto){ | |
| 102 | + global $convUTF; | |
| 103 | + if($convUTF == true) | |
| 104 | + $texto = mb_convert_encoding($texto,mb_detect_encoding($texto),"UTF-8"); | |
| 105 | + else | |
| 106 | + $texto = mb_convert_encoding($texto,mb_detect_encoding($texto),"ISO-8859-1"); | |
| 107 | + return $texto; | |
| 108 | +} | |
| 109 | +?> | |
| 110 | +<script> | |
| 111 | + | |
| 112 | +</script> | |
| 0 | 113 | \ No newline at end of file | ... | ... |
guia_de_migracao.txt
| ... | ... | @@ -18,7 +18,13 @@ Para a versão 4.5 |
| 18 | 18 | |
| 19 | 19 | A pasta "images" foi removida e as imagens movidas para a pasta "imagens\depreciado" |
| 20 | 20 | |
| 21 | - | |
| 21 | + Opção de comentários em temas | |
| 22 | + Foram acrescentadas novas variáveis em ms_configura.php. Veja esse arquivo para editar as variáveis e registrar | |
| 23 | + as APIs das redes sociais como Twitter e Facebook | |
| 24 | + Por default, todos os temas podem receber comentários. Para bloquear comentários em temas específicos, | |
| 25 | + utilize o editor de mapfiles do sistema de admnistração | |
| 26 | + Os comentários são armazenados em uma tabela no banco de dados de administração. Essa tabela precisa ser criada no banco. | |
| 27 | + Para criar a tabela veja o item "Outras opções" em http://localhost/i3geo/admin | |
| 22 | 28 | |
| 23 | 29 | ------------------------------------------------------------------------------------------------- |
| 24 | 30 | Para a versão 4.4 | ... | ... |
2.3 KB
2.66 KB
5.99 KB
3.65 KB
5.59 KB
1.42 KB
1.11 KB
4.76 KB
3.99 KB
3.77 KB
interface/googlemaps.phtml
| ... | ... | @@ -141,6 +141,8 @@ i3GEO.idioma.IDSELETOR = "seletorIdiomas"; |
| 141 | 141 | i3GEO.Interface.ATIVAMENUCONTEXTO = true; |
| 142 | 142 | i3GEO.arvoreDeTemas.TIPOBOTAO = "radio"; |
| 143 | 143 | i3GEO.arvoreDeTemas.ATIVATEMAIMEDIATO = true; |
| 144 | +//para evitar a entrada de comentários na árvore de camadas, modifique a opção de cada tema individualmente no sistema de administração | |
| 145 | +i3GEO.arvoreDeTemas.OPCOESADICIONAIS.comentario = true; | |
| 144 | 146 | |
| 145 | 147 | i3GEO.inicia(); |
| 146 | 148 | </script> | ... | ... |
ms_configura.php
| ... | ... | @@ -43,6 +43,96 @@ Arquivo: ms_configura.php |
| 43 | 43 | |
| 44 | 44 | */ |
| 45 | 45 | /* |
| 46 | + Variavel: linkedinoauth (ainda não implementado) | |
| 47 | + | |
| 48 | + Parâmetros registrados no Linkedin para permitir que o i3Geo faça autenticação com base na conta do usuário | |
| 49 | + | |
| 50 | + O Linkedin exige que cada site seja registrado para permitir que a API de autenticação funcione | |
| 51 | + | |
| 52 | + Veja o site para maiores informações: http://developer.linkedin.com/docs/DOC-1008 | |
| 53 | + | |
| 54 | + Caso vc não queira permitir essa opção, deixe essa variável vazia, e.x | |
| 55 | + | |
| 56 | + Ao registrar utilize o valor http://meuservidor/i3geo/pacotes/openid/login.php?login | |
| 57 | + | |
| 58 | + Exemplo: | |
| 59 | + | |
| 60 | + $linkedinoauth = array( | |
| 61 | + "consumerkey" => "0oQ30ge-ggKarx4HGaXVK118n8mekMBbFYTrC-agGV9hvxUXfeWwS1q7ZMvD-8LL", | |
| 62 | + "consumersecret" => "nRGXfHp1XNMt0eCG7tWJpoCcXX1uoZseDtgiU-CRy1ajqipo4KpjjZdDUXmqZGQA" | |
| 63 | + ); | |
| 64 | + | |
| 65 | + Tipo: | |
| 66 | + {array} | |
| 67 | +*/ | |
| 68 | +$linkedinoauth = ""; | |
| 69 | +/* | |
| 70 | + Variavel: facebookoauth | |
| 71 | + | |
| 72 | + Parâmetros registrados no Facebook para permitir que o i3Geo faça autenticação com base na conta do usuário | |
| 73 | + | |
| 74 | + O Facebook exige que cada site seja registrado para permitir que a API de autenticação funcione | |
| 75 | + | |
| 76 | + Veja o site para maiores informações: http://developers.facebook.com/setup/ | |
| 77 | + | |
| 78 | + Caso vc não queira permitir essa opção, deixe essa variável vazia, e.x | |
| 79 | + | |
| 80 | + Ao registrar utilize o valor http://meuservidor/i3geo/pacotes/openid/login.php?login | |
| 81 | + | |
| 82 | + Exemplo: | |
| 83 | + | |
| 84 | + $facebookoauth = array( | |
| 85 | + "consumerkey" => "136279263094148", | |
| 86 | + "consumersecret" => "679fc4a007b1d289377fa8af8f7086b6" | |
| 87 | + ); | |
| 88 | + | |
| 89 | + Tipo: | |
| 90 | + {array} | |
| 91 | +*/ | |
| 92 | +$facebookoauth = array( | |
| 93 | + "consumerkey" => "136279263094148", | |
| 94 | + "consumersecret" => "679fc4a007b1d289377fa8af8f7086b6" | |
| 95 | + ); | |
| 96 | +/* | |
| 97 | + Variavel: twitteroauth | |
| 98 | + | |
| 99 | + Parâmetros registrados no Twitter para permitir que o i3Geo faça autenticação com base na conta do usuário | |
| 100 | + | |
| 101 | + O Twitter exige que cada site seja registrado para permitir que a API de autenticação funcione | |
| 102 | + | |
| 103 | + Veja o site para maiores informações: http://www.snipe.net/2009/07/writing-your-first-twitter-application-with-oauth/ | |
| 104 | + | |
| 105 | + Lista de aplicações cadastradas: https://twitter.com/oauth_clients/ | |
| 106 | + | |
| 107 | + Caso vc não queira permitir essa opção, deixe essa variável vazia, e.x | |
| 108 | + | |
| 109 | + $twitteroauth = ""; | |
| 110 | + | |
| 111 | + Ao registrar a aplicação, utilize o endereço do i3geo em Application Website, por exemplo http://meuservidor/i3geo | |
| 112 | + | |
| 113 | + Ao registrar utilize como "Callback URL" o valor http://meuservidor/i3geo/pacotes/openid/login.php?login | |
| 114 | + | |
| 115 | + Exemplo: | |
| 116 | + | |
| 117 | + $twitteroauth = array( | |
| 118 | + "consumerkey" => "vUvBcsOULjS0ewxuSvbS6w", | |
| 119 | + "consumersecret" => "0Hj6uCyycDCeNOgzTUF1bBSel75KtfbnCS4bxWVqaxk", | |
| 120 | + "requesttokenurl" => "https://twitter.com/oauth/request_token", | |
| 121 | + "accesstokenurl" => "https://twitter.com/oauth/access_token", | |
| 122 | + "authorizeurl" => "https://twitter.com/oauth/authorize" | |
| 123 | + ); | |
| 124 | + | |
| 125 | + Tipo: | |
| 126 | + {array} | |
| 127 | +*/ | |
| 128 | +$twitteroauth = array( | |
| 129 | + "consumerkey" => "vUvBcsOULjS0ewxuSvbS6w", | |
| 130 | + "consumersecret" => "0Hj6uCyycDCeNOgzTUF1bBSel75KtfbnCS4bxWVqaxk", | |
| 131 | + "requesttokenurl" => "https://twitter.com/oauth/request_token", | |
| 132 | + "accesstokenurl" => "https://twitter.com/oauth/access_token", | |
| 133 | + "authorizeurl" => "https://twitter.com/oauth/authorize" | |
| 134 | + ); | |
| 135 | +/* | |
| 46 | 136 | Variavel: mensagemInicia |
| 47 | 137 | |
| 48 | 138 | Mensagem de inicialização mostrada pelo programa ms_criamapa.php | ... | ... |
| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * @file | |
| 4 | + * Take the user when they return from Twitter. Get access tokens. | |
| 5 | + * Verify credentials and redirect to based on response from Twitter. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +/* Start session and load lib */ | |
| 9 | +$par = array_merge($_GET,$_POST); | |
| 10 | +session_name("openid"); | |
| 11 | +session_start(); | |
| 12 | +$_SESSION["openid"] = true; | |
| 13 | +$_SESSION["openid_identifier"] = $par["openid_identifier"]; | |
| 14 | +$_SESSION["openidusuario"] = basename($_SESSION["openid_identifier"]); | |
| 15 | +$_SESSION["openidservico"] = "facebook"; | |
| 16 | +$_SESSION["openidimagem"] = "http://graph.facebook.com/".$_SESSION["openidusuario"]."/picture"; | |
| 17 | +$_SESSION["openidnome"] = $par["openidnome"]; | |
| 18 | +header('Location: '.$_SESSION["urlVolta"]); | |
| 19 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * @file | |
| 4 | + * Clears PHP sessions and redirects to the connect page. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +/* Load and clear sessions */ | |
| 8 | +session_start("openid"); | |
| 9 | +session_destroy(); | |
| 10 | + | |
| 11 | +/* Redirect to page with the connect to Twitter option. */ | |
| 12 | +header('Location: ../openid/login.php?login&erro=ok'); | |
| 13 | +?> | |
| 0 | 14 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | +<?php | |
| 2 | +session_name("openid"); | |
| 3 | +session_start(); | |
| 4 | +require_once('config.php'); | |
| 5 | +?> | |
| 6 | +<html> | |
| 7 | +<div id="fb-root"></div> | |
| 8 | +<script src="http://connect.facebook.net/en_US/all.js"></script> | |
| 9 | +<body onload="inicia()"> | |
| 10 | +<script> | |
| 11 | + function inicia(){ | |
| 12 | + FB.init({appId: '<?php echo FACEBOOK_APP_ID;?>', status: true, cookie: true, xfbml: true}); | |
| 13 | + | |
| 14 | + FB.login(function(response) { | |
| 15 | + if (response.session) { | |
| 16 | + FB.api('/me', | |
| 17 | + function(response) { | |
| 18 | + window.location.href = "callback.php?openid_identifier="+response.link+"&openidnome="+response.name; | |
| 19 | + } | |
| 20 | + ); | |
| 21 | + } else { | |
| 22 | + window.location.href = "clearsessions.php"; | |
| 23 | + } | |
| 24 | + }); | |
| 25 | + } | |
| 26 | +</script> | |
| 27 | +</body> | |
| 28 | +</html> | |
| 0 | 29 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | +== 2008.08.04 == | |
| 2 | +* Added LICENSE.txt file with MIT license, copyright owner is perhaps | |
| 3 | + dubious however. | |
| 4 | +== 2008.07.22 == | |
| 5 | +* Change to encoding to fix last change to encoding of spaces | |
| 6 | +== 2008.07.15 == | |
| 7 | +* Another change to encoding per | |
| 8 | + http://groups.google.com/group/oauth/browse_thread/thread/d39931d39b4af4bd | |
| 9 | +* A change to port handling to better deal with https and the like per | |
| 10 | + http://groups.google.com/group/oauth/browse_thread/thread/1b203a51d9590226 | |
| 11 | +* Fixed a small bug per | |
| 12 | + http://code.google.com/p/oauth/issues/detail?id=26 | |
| 13 | +* Added missing base_string debug info when using RSA-SHA1 | |
| 14 | +* Increased size of example endpoint input field and added note about | |
| 15 | + query strings | ... | ... |
| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | +The MIT License | |
| 2 | + | |
| 3 | +Copyright (c) 2007 Andy Smith | |
| 4 | + | |
| 5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 6 | +of this software and associated documentation files (the "Software"), to deal | |
| 7 | +in the Software without restriction, including without limitation the rights | |
| 8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 9 | +copies of the Software, and to permit persons to whom the Software is | |
| 10 | +furnished to do so, subject to the following conditions: | |
| 11 | + | |
| 12 | +The above copyright notice and this permission notice shall be included in | |
| 13 | +all copies or substantial portions of the Software. | |
| 14 | + | |
| 15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 21 | +THE SOFTWARE. | |
| 22 | + | ... | ... |
| ... | ... | @@ -0,0 +1,866 @@ |
| 1 | +<?php | |
| 2 | +// vim: foldmethod=marker | |
| 3 | + | |
| 4 | +/* Generic exception class | |
| 5 | + */ | |
| 6 | +class OAuthException extends Exception { | |
| 7 | + // pass | |
| 8 | +} | |
| 9 | + | |
| 10 | +class OAuthConsumer { | |
| 11 | + public $key; | |
| 12 | + public $secret; | |
| 13 | + | |
| 14 | + function __construct($key, $secret, $callback_url=NULL) { | |
| 15 | + $this->key = $key; | |
| 16 | + $this->secret = $secret; | |
| 17 | + $this->callback_url = $callback_url; | |
| 18 | + } | |
| 19 | + | |
| 20 | + function __toString() { | |
| 21 | + return "OAuthConsumer[key=$this->key,secret=$this->secret]"; | |
| 22 | + } | |
| 23 | +} | |
| 24 | + | |
| 25 | +class OAuthToken { | |
| 26 | + // access tokens and request tokens | |
| 27 | + public $key; | |
| 28 | + public $secret; | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * key = the token | |
| 32 | + * secret = the token secret | |
| 33 | + */ | |
| 34 | + function __construct($key, $secret) { | |
| 35 | + $this->key = $key; | |
| 36 | + $this->secret = $secret; | |
| 37 | + } | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * generates the basic string serialization of a token that a server | |
| 41 | + * would respond to request_token and access_token calls with | |
| 42 | + */ | |
| 43 | + function to_string() { | |
| 44 | + return "oauth_token=" . | |
| 45 | + OAuthUtil::urlencode_rfc3986($this->key) . | |
| 46 | + "&oauth_token_secret=" . | |
| 47 | + OAuthUtil::urlencode_rfc3986($this->secret); | |
| 48 | + } | |
| 49 | + | |
| 50 | + function __toString() { | |
| 51 | + return $this->to_string(); | |
| 52 | + } | |
| 53 | +} | |
| 54 | + | |
| 55 | +/** | |
| 56 | + * A class for implementing a Signature Method | |
| 57 | + * See section 9 ("Signing Requests") in the spec | |
| 58 | + */ | |
| 59 | +abstract class OAuthSignatureMethod { | |
| 60 | + /** | |
| 61 | + * Needs to return the name of the Signature Method (ie HMAC-SHA1) | |
| 62 | + * @return string | |
| 63 | + */ | |
| 64 | + abstract public function get_name(); | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Build up the signature | |
| 68 | + * NOTE: The output of this function MUST NOT be urlencoded. | |
| 69 | + * the encoding is handled in OAuthRequest when the final | |
| 70 | + * request is serialized | |
| 71 | + * @param OAuthRequest $request | |
| 72 | + * @param OAuthConsumer $consumer | |
| 73 | + * @param OAuthToken $token | |
| 74 | + * @return string | |
| 75 | + */ | |
| 76 | + abstract public function build_signature($request, $consumer, $token); | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * Verifies that a given signature is correct | |
| 80 | + * @param OAuthRequest $request | |
| 81 | + * @param OAuthConsumer $consumer | |
| 82 | + * @param OAuthToken $token | |
| 83 | + * @param string $signature | |
| 84 | + * @return bool | |
| 85 | + */ | |
| 86 | + public function check_signature($request, $consumer, $token, $signature) { | |
| 87 | + $built = $this->build_signature($request, $consumer, $token); | |
| 88 | + return $built == $signature; | |
| 89 | + } | |
| 90 | +} | |
| 91 | + | |
| 92 | +/** | |
| 93 | + * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] | |
| 94 | + * where the Signature Base String is the text and the key is the concatenated values (each first | |
| 95 | + * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' | |
| 96 | + * character (ASCII code 38) even if empty. | |
| 97 | + * - Chapter 9.2 ("HMAC-SHA1") | |
| 98 | + */ | |
| 99 | +class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { | |
| 100 | + function get_name() { | |
| 101 | + return "HMAC-SHA1"; | |
| 102 | + } | |
| 103 | + | |
| 104 | + public function build_signature($request, $consumer, $token) { | |
| 105 | + $base_string = $request->get_signature_base_string(); | |
| 106 | + $request->base_string = $base_string; | |
| 107 | + | |
| 108 | + $key_parts = array( | |
| 109 | + $consumer->secret, | |
| 110 | + ($token) ? $token->secret : "" | |
| 111 | + ); | |
| 112 | + | |
| 113 | + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); | |
| 114 | + $key = implode('&', $key_parts); | |
| 115 | + | |
| 116 | + return base64_encode(hash_hmac('sha1', $base_string, $key, true)); | |
| 117 | + } | |
| 118 | +} | |
| 119 | + | |
| 120 | +/** | |
| 121 | + * The PLAINTEXT method does not provide any security protection and SHOULD only be used | |
| 122 | + * over a secure channel such as HTTPS. It does not use the Signature Base String. | |
| 123 | + * - Chapter 9.4 ("PLAINTEXT") | |
| 124 | + */ | |
| 125 | +class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { | |
| 126 | + public function get_name() { | |
| 127 | + return "PLAINTEXT"; | |
| 128 | + } | |
| 129 | + | |
| 130 | + /** | |
| 131 | + * oauth_signature is set to the concatenated encoded values of the Consumer Secret and | |
| 132 | + * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is | |
| 133 | + * empty. The result MUST be encoded again. | |
| 134 | + * - Chapter 9.4.1 ("Generating Signatures") | |
| 135 | + * | |
| 136 | + * Please note that the second encoding MUST NOT happen in the SignatureMethod, as | |
| 137 | + * OAuthRequest handles this! | |
| 138 | + */ | |
| 139 | + public function build_signature($request, $consumer, $token) { | |
| 140 | + $key_parts = array( | |
| 141 | + $consumer->secret, | |
| 142 | + ($token) ? $token->secret : "" | |
| 143 | + ); | |
| 144 | + | |
| 145 | + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); | |
| 146 | + $key = implode('&', $key_parts); | |
| 147 | + $request->base_string = $key; | |
| 148 | + | |
| 149 | + return $key; | |
| 150 | + } | |
| 151 | +} | |
| 152 | + | |
| 153 | +/** | |
| 154 | + * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in | |
| 155 | + * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for | |
| 156 | + * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a | |
| 157 | + * verified way to the Service Provider, in a manner which is beyond the scope of this | |
| 158 | + * specification. | |
| 159 | + * - Chapter 9.3 ("RSA-SHA1") | |
| 160 | + */ | |
| 161 | +abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { | |
| 162 | + public function get_name() { | |
| 163 | + return "RSA-SHA1"; | |
| 164 | + } | |
| 165 | + | |
| 166 | + // Up to the SP to implement this lookup of keys. Possible ideas are: | |
| 167 | + // (1) do a lookup in a table of trusted certs keyed off of consumer | |
| 168 | + // (2) fetch via http using a url provided by the requester | |
| 169 | + // (3) some sort of specific discovery code based on request | |
| 170 | + // | |
| 171 | + // Either way should return a string representation of the certificate | |
| 172 | + protected abstract function fetch_public_cert(&$request); | |
| 173 | + | |
| 174 | + // Up to the SP to implement this lookup of keys. Possible ideas are: | |
| 175 | + // (1) do a lookup in a table of trusted certs keyed off of consumer | |
| 176 | + // | |
| 177 | + // Either way should return a string representation of the certificate | |
| 178 | + protected abstract function fetch_private_cert(&$request); | |
| 179 | + | |
| 180 | + public function build_signature($request, $consumer, $token) { | |
| 181 | + $base_string = $request->get_signature_base_string(); | |
| 182 | + $request->base_string = $base_string; | |
| 183 | + | |
| 184 | + // Fetch the private key cert based on the request | |
| 185 | + $cert = $this->fetch_private_cert($request); | |
| 186 | + | |
| 187 | + // Pull the private key ID from the certificate | |
| 188 | + $privatekeyid = openssl_get_privatekey($cert); | |
| 189 | + | |
| 190 | + // Sign using the key | |
| 191 | + $ok = openssl_sign($base_string, $signature, $privatekeyid); | |
| 192 | + | |
| 193 | + // Release the key resource | |
| 194 | + openssl_free_key($privatekeyid); | |
| 195 | + | |
| 196 | + return base64_encode($signature); | |
| 197 | + } | |
| 198 | + | |
| 199 | + public function check_signature($request, $consumer, $token, $signature) { | |
| 200 | + $decoded_sig = base64_decode($signature); | |
| 201 | + | |
| 202 | + $base_string = $request->get_signature_base_string(); | |
| 203 | + | |
| 204 | + // Fetch the public key cert based on the request | |
| 205 | + $cert = $this->fetch_public_cert($request); | |
| 206 | + | |
| 207 | + // Pull the public key ID from the certificate | |
| 208 | + $publickeyid = openssl_get_publickey($cert); | |
| 209 | + | |
| 210 | + // Check the computed signature against the one passed in the query | |
| 211 | + $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); | |
| 212 | + | |
| 213 | + // Release the key resource | |
| 214 | + openssl_free_key($publickeyid); | |
| 215 | + | |
| 216 | + return $ok == 1; | |
| 217 | + } | |
| 218 | +} | |
| 219 | + | |
| 220 | +class OAuthRequest { | |
| 221 | + private $parameters; | |
| 222 | + private $http_method; | |
| 223 | + private $http_url; | |
| 224 | + // for debug purposes | |
| 225 | + public $base_string; | |
| 226 | + public static $version = '1.0'; | |
| 227 | + public static $POST_INPUT = 'php://input'; | |
| 228 | + | |
| 229 | + function __construct($http_method, $http_url, $parameters=NULL) { | |
| 230 | + @$parameters or $parameters = array(); | |
| 231 | + $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters); | |
| 232 | + $this->parameters = $parameters; | |
| 233 | + $this->http_method = $http_method; | |
| 234 | + $this->http_url = $http_url; | |
| 235 | + } | |
| 236 | + | |
| 237 | + | |
| 238 | + /** | |
| 239 | + * attempt to build up a request from what was passed to the server | |
| 240 | + */ | |
| 241 | + public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { | |
| 242 | + $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") | |
| 243 | + ? 'http' | |
| 244 | + : 'https'; | |
| 245 | + @$http_url or $http_url = $scheme . | |
| 246 | + '://' . $_SERVER['HTTP_HOST'] . | |
| 247 | + ':' . | |
| 248 | + $_SERVER['SERVER_PORT'] . | |
| 249 | + $_SERVER['REQUEST_URI']; | |
| 250 | + @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; | |
| 251 | + | |
| 252 | + // We weren't handed any parameters, so let's find the ones relevant to | |
| 253 | + // this request. | |
| 254 | + // If you run XML-RPC or similar you should use this to provide your own | |
| 255 | + // parsed parameter-list | |
| 256 | + if (!$parameters) { | |
| 257 | + // Find request headers | |
| 258 | + $request_headers = OAuthUtil::get_headers(); | |
| 259 | + | |
| 260 | + // Parse the query-string to find GET parameters | |
| 261 | + $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); | |
| 262 | + | |
| 263 | + // It's a POST request of the proper content-type, so parse POST | |
| 264 | + // parameters and add those overriding any duplicates from GET | |
| 265 | + if ($http_method == "POST" | |
| 266 | + && @strstr($request_headers["Content-Type"], | |
| 267 | + "application/x-www-form-urlencoded") | |
| 268 | + ) { | |
| 269 | + $post_data = OAuthUtil::parse_parameters( | |
| 270 | + file_get_contents(self::$POST_INPUT) | |
| 271 | + ); | |
| 272 | + $parameters = array_merge($parameters, $post_data); | |
| 273 | + } | |
| 274 | + | |
| 275 | + // We have a Authorization-header with OAuth data. Parse the header | |
| 276 | + // and add those overriding any duplicates from GET or POST | |
| 277 | + if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { | |
| 278 | + $header_parameters = OAuthUtil::split_header( | |
| 279 | + $request_headers['Authorization'] | |
| 280 | + ); | |
| 281 | + $parameters = array_merge($parameters, $header_parameters); | |
| 282 | + } | |
| 283 | + | |
| 284 | + } | |
| 285 | + | |
| 286 | + return new OAuthRequest($http_method, $http_url, $parameters); | |
| 287 | + } | |
| 288 | + | |
| 289 | + /** | |
| 290 | + * pretty much a helper function to set up the request | |
| 291 | + */ | |
| 292 | + public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { | |
| 293 | + @$parameters or $parameters = array(); | |
| 294 | + $defaults = array("oauth_version" => OAuthRequest::$version, | |
| 295 | + "oauth_nonce" => OAuthRequest::generate_nonce(), | |
| 296 | + "oauth_timestamp" => OAuthRequest::generate_timestamp(), | |
| 297 | + "oauth_consumer_key" => $consumer->key); | |
| 298 | + if ($token) | |
| 299 | + $defaults['oauth_token'] = $token->key; | |
| 300 | + | |
| 301 | + $parameters = array_merge($defaults, $parameters); | |
| 302 | + | |
| 303 | + return new OAuthRequest($http_method, $http_url, $parameters); | |
| 304 | + } | |
| 305 | + | |
| 306 | + public function set_parameter($name, $value, $allow_duplicates = true) { | |
| 307 | + if ($allow_duplicates && isset($this->parameters[$name])) { | |
| 308 | + // We have already added parameter(s) with this name, so add to the list | |
| 309 | + if (is_scalar($this->parameters[$name])) { | |
| 310 | + // This is the first duplicate, so transform scalar (string) | |
| 311 | + // into an array so we can add the duplicates | |
| 312 | + $this->parameters[$name] = array($this->parameters[$name]); | |
| 313 | + } | |
| 314 | + | |
| 315 | + $this->parameters[$name][] = $value; | |
| 316 | + } else { | |
| 317 | + $this->parameters[$name] = $value; | |
| 318 | + } | |
| 319 | + } | |
| 320 | + | |
| 321 | + public function get_parameter($name) { | |
| 322 | + return isset($this->parameters[$name]) ? $this->parameters[$name] : null; | |
| 323 | + } | |
| 324 | + | |
| 325 | + public function get_parameters() { | |
| 326 | + return $this->parameters; | |
| 327 | + } | |
| 328 | + | |
| 329 | + public function unset_parameter($name) { | |
| 330 | + unset($this->parameters[$name]); | |
| 331 | + } | |
| 332 | + | |
| 333 | + /** | |
| 334 | + * The request parameters, sorted and concatenated into a normalized string. | |
| 335 | + * @return string | |
| 336 | + */ | |
| 337 | + public function get_signable_parameters() { | |
| 338 | + // Grab all parameters | |
| 339 | + $params = $this->parameters; | |
| 340 | + | |
| 341 | + // Remove oauth_signature if present | |
| 342 | + // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") | |
| 343 | + if (isset($params['oauth_signature'])) { | |
| 344 | + unset($params['oauth_signature']); | |
| 345 | + } | |
| 346 | + | |
| 347 | + return OAuthUtil::build_http_query($params); | |
| 348 | + } | |
| 349 | + | |
| 350 | + /** | |
| 351 | + * Returns the base string of this request | |
| 352 | + * | |
| 353 | + * The base string defined as the method, the url | |
| 354 | + * and the parameters (normalized), each urlencoded | |
| 355 | + * and the concated with &. | |
| 356 | + */ | |
| 357 | + public function get_signature_base_string() { | |
| 358 | + $parts = array( | |
| 359 | + $this->get_normalized_http_method(), | |
| 360 | + $this->get_normalized_http_url(), | |
| 361 | + $this->get_signable_parameters() | |
| 362 | + ); | |
| 363 | + | |
| 364 | + $parts = OAuthUtil::urlencode_rfc3986($parts); | |
| 365 | + | |
| 366 | + return implode('&', $parts); | |
| 367 | + } | |
| 368 | + | |
| 369 | + /** | |
| 370 | + * just uppercases the http method | |
| 371 | + */ | |
| 372 | + public function get_normalized_http_method() { | |
| 373 | + return strtoupper($this->http_method); | |
| 374 | + } | |
| 375 | + | |
| 376 | + /** | |
| 377 | + * parses the url and rebuilds it to be | |
| 378 | + * scheme://host/path | |
| 379 | + */ | |
| 380 | + public function get_normalized_http_url() { | |
| 381 | + $parts = parse_url($this->http_url); | |
| 382 | + | |
| 383 | + $port = @$parts['port']; | |
| 384 | + $scheme = $parts['scheme']; | |
| 385 | + $host = $parts['host']; | |
| 386 | + $path = @$parts['path']; | |
| 387 | + | |
| 388 | + $port or $port = ($scheme == 'https') ? '443' : '80'; | |
| 389 | + | |
| 390 | + if (($scheme == 'https' && $port != '443') | |
| 391 | + || ($scheme == 'http' && $port != '80')) { | |
| 392 | + $host = "$host:$port"; | |
| 393 | + } | |
| 394 | + return "$scheme://$host$path"; | |
| 395 | + } | |
| 396 | + | |
| 397 | + /** | |
| 398 | + * builds a url usable for a GET request | |
| 399 | + */ | |
| 400 | + public function to_url() { | |
| 401 | + $post_data = $this->to_postdata(); | |
| 402 | + $out = $this->get_normalized_http_url(); | |
| 403 | + if ($post_data) { | |
| 404 | + $out .= '?'.$post_data; | |
| 405 | + } | |
| 406 | + return $out; | |
| 407 | + } | |
| 408 | + | |
| 409 | + /** | |
| 410 | + * builds the data one would send in a POST request | |
| 411 | + */ | |
| 412 | + public function to_postdata() { | |
| 413 | + return OAuthUtil::build_http_query($this->parameters); | |
| 414 | + } | |
| 415 | + | |
| 416 | + /** | |
| 417 | + * builds the Authorization: header | |
| 418 | + */ | |
| 419 | + public function to_header($realm=null) { | |
| 420 | + if($realm) | |
| 421 | + $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; | |
| 422 | + else | |
| 423 | + $out = 'Authorization: OAuth'; | |
| 424 | + | |
| 425 | + $total = array(); | |
| 426 | + foreach ($this->parameters as $k => $v) { | |
| 427 | + if (substr($k, 0, 5) != "oauth") continue; | |
| 428 | + if (is_array($v)) { | |
| 429 | + throw new OAuthException('Arrays not supported in headers'); | |
| 430 | + } | |
| 431 | + $out .= ',' . | |
| 432 | + OAuthUtil::urlencode_rfc3986($k) . | |
| 433 | + '="' . | |
| 434 | + OAuthUtil::urlencode_rfc3986($v) . | |
| 435 | + '"'; | |
| 436 | + } | |
| 437 | + return $out; | |
| 438 | + } | |
| 439 | + | |
| 440 | + public function __toString() { | |
| 441 | + return $this->to_url(); | |
| 442 | + } | |
| 443 | + | |
| 444 | + | |
| 445 | + public function sign_request($signature_method, $consumer, $token) { | |
| 446 | + $this->set_parameter( | |
| 447 | + "oauth_signature_method", | |
| 448 | + $signature_method->get_name(), | |
| 449 | + false | |
| 450 | + ); | |
| 451 | + $signature = $this->build_signature($signature_method, $consumer, $token); | |
| 452 | + $this->set_parameter("oauth_signature", $signature, false); | |
| 453 | + } | |
| 454 | + | |
| 455 | + public function build_signature($signature_method, $consumer, $token) { | |
| 456 | + $signature = $signature_method->build_signature($this, $consumer, $token); | |
| 457 | + return $signature; | |
| 458 | + } | |
| 459 | + | |
| 460 | + /** | |
| 461 | + * util function: current timestamp | |
| 462 | + */ | |
| 463 | + private static function generate_timestamp() { | |
| 464 | + return time(); | |
| 465 | + } | |
| 466 | + | |
| 467 | + /** | |
| 468 | + * util function: current nonce | |
| 469 | + */ | |
| 470 | + private static function generate_nonce() { | |
| 471 | + $mt = microtime(); | |
| 472 | + $rand = mt_rand(); | |
| 473 | + | |
| 474 | + return md5($mt . $rand); // md5s look nicer than numbers | |
| 475 | + } | |
| 476 | +} | |
| 477 | + | |
| 478 | +class OAuthServer { | |
| 479 | + protected $timestamp_threshold = 300; // in seconds, five minutes | |
| 480 | + protected $version = '1.0'; // hi blaine | |
| 481 | + protected $signature_methods = array(); | |
| 482 | + | |
| 483 | + protected $data_store; | |
| 484 | + | |
| 485 | + function __construct($data_store) { | |
| 486 | + $this->data_store = $data_store; | |
| 487 | + } | |
| 488 | + | |
| 489 | + public function add_signature_method($signature_method) { | |
| 490 | + $this->signature_methods[$signature_method->get_name()] = | |
| 491 | + $signature_method; | |
| 492 | + } | |
| 493 | + | |
| 494 | + // high level functions | |
| 495 | + | |
| 496 | + /** | |
| 497 | + * process a request_token request | |
| 498 | + * returns the request token on success | |
| 499 | + */ | |
| 500 | + public function fetch_request_token(&$request) { | |
| 501 | + $this->get_version($request); | |
| 502 | + | |
| 503 | + $consumer = $this->get_consumer($request); | |
| 504 | + | |
| 505 | + // no token required for the initial token request | |
| 506 | + $token = NULL; | |
| 507 | + | |
| 508 | + $this->check_signature($request, $consumer, $token); | |
| 509 | + | |
| 510 | + // Rev A change | |
| 511 | + $callback = $request->get_parameter('oauth_callback'); | |
| 512 | + $new_token = $this->data_store->new_request_token($consumer, $callback); | |
| 513 | + | |
| 514 | + return $new_token; | |
| 515 | + } | |
| 516 | + | |
| 517 | + /** | |
| 518 | + * process an access_token request | |
| 519 | + * returns the access token on success | |
| 520 | + */ | |
| 521 | + public function fetch_access_token(&$request) { | |
| 522 | + $this->get_version($request); | |
| 523 | + | |
| 524 | + $consumer = $this->get_consumer($request); | |
| 525 | + | |
| 526 | + // requires authorized request token | |
| 527 | + $token = $this->get_token($request, $consumer, "request"); | |
| 528 | + | |
| 529 | + $this->check_signature($request, $consumer, $token); | |
| 530 | + | |
| 531 | + // Rev A change | |
| 532 | + $verifier = $request->get_parameter('oauth_verifier'); | |
| 533 | + $new_token = $this->data_store->new_access_token($token, $consumer, $verifier); | |
| 534 | + | |
| 535 | + return $new_token; | |
| 536 | + } | |
| 537 | + | |
| 538 | + /** | |
| 539 | + * verify an api call, checks all the parameters | |
| 540 | + */ | |
| 541 | + public function verify_request(&$request) { | |
| 542 | + $this->get_version($request); | |
| 543 | + $consumer = $this->get_consumer($request); | |
| 544 | + $token = $this->get_token($request, $consumer, "access"); | |
| 545 | + $this->check_signature($request, $consumer, $token); | |
| 546 | + return array($consumer, $token); | |
| 547 | + } | |
| 548 | + | |
| 549 | + // Internals from here | |
| 550 | + /** | |
| 551 | + * version 1 | |
| 552 | + */ | |
| 553 | + private function get_version(&$request) { | |
| 554 | + $version = $request->get_parameter("oauth_version"); | |
| 555 | + if (!$version) { | |
| 556 | + // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. | |
| 557 | + // Chapter 7.0 ("Accessing Protected Ressources") | |
| 558 | + $version = '1.0'; | |
| 559 | + } | |
| 560 | + if ($version !== $this->version) { | |
| 561 | + throw new OAuthException("OAuth version '$version' not supported"); | |
| 562 | + } | |
| 563 | + return $version; | |
| 564 | + } | |
| 565 | + | |
| 566 | + /** | |
| 567 | + * figure out the signature with some defaults | |
| 568 | + */ | |
| 569 | + private function get_signature_method(&$request) { | |
| 570 | + $signature_method = | |
| 571 | + @$request->get_parameter("oauth_signature_method"); | |
| 572 | + | |
| 573 | + if (!$signature_method) { | |
| 574 | + // According to chapter 7 ("Accessing Protected Ressources") the signature-method | |
| 575 | + // parameter is required, and we can't just fallback to PLAINTEXT | |
| 576 | + throw new OAuthException('No signature method parameter. This parameter is required'); | |
| 577 | + } | |
| 578 | + | |
| 579 | + if (!in_array($signature_method, | |
| 580 | + array_keys($this->signature_methods))) { | |
| 581 | + throw new OAuthException( | |
| 582 | + "Signature method '$signature_method' not supported " . | |
| 583 | + "try one of the following: " . | |
| 584 | + implode(", ", array_keys($this->signature_methods)) | |
| 585 | + ); | |
| 586 | + } | |
| 587 | + return $this->signature_methods[$signature_method]; | |
| 588 | + } | |
| 589 | + | |
| 590 | + /** | |
| 591 | + * try to find the consumer for the provided request's consumer key | |
| 592 | + */ | |
| 593 | + private function get_consumer(&$request) { | |
| 594 | + $consumer_key = @$request->get_parameter("oauth_consumer_key"); | |
| 595 | + if (!$consumer_key) { | |
| 596 | + throw new OAuthException("Invalid consumer key"); | |
| 597 | + } | |
| 598 | + | |
| 599 | + $consumer = $this->data_store->lookup_consumer($consumer_key); | |
| 600 | + if (!$consumer) { | |
| 601 | + throw new OAuthException("Invalid consumer"); | |
| 602 | + } | |
| 603 | + | |
| 604 | + return $consumer; | |
| 605 | + } | |
| 606 | + | |
| 607 | + /** | |
| 608 | + * try to find the token for the provided request's token key | |
| 609 | + */ | |
| 610 | + private function get_token(&$request, $consumer, $token_type="access") { | |
| 611 | + $token_field = @$request->get_parameter('oauth_token'); | |
| 612 | + $token = $this->data_store->lookup_token( | |
| 613 | + $consumer, $token_type, $token_field | |
| 614 | + ); | |
| 615 | + if (!$token) { | |
| 616 | + throw new OAuthException("Invalid $token_type token: $token_field"); | |
| 617 | + } | |
| 618 | + return $token; | |
| 619 | + } | |
| 620 | + | |
| 621 | + /** | |
| 622 | + * all-in-one function to check the signature on a request | |
| 623 | + * should guess the signature method appropriately | |
| 624 | + */ | |
| 625 | + private function check_signature(&$request, $consumer, $token) { | |
| 626 | + // this should probably be in a different method | |
| 627 | + $timestamp = @$request->get_parameter('oauth_timestamp'); | |
| 628 | + $nonce = @$request->get_parameter('oauth_nonce'); | |
| 629 | + | |
| 630 | + $this->check_timestamp($timestamp); | |
| 631 | + $this->check_nonce($consumer, $token, $nonce, $timestamp); | |
| 632 | + | |
| 633 | + $signature_method = $this->get_signature_method($request); | |
| 634 | + | |
| 635 | + $signature = $request->get_parameter('oauth_signature'); | |
| 636 | + $valid_sig = $signature_method->check_signature( | |
| 637 | + $request, | |
| 638 | + $consumer, | |
| 639 | + $token, | |
| 640 | + $signature | |
| 641 | + ); | |
| 642 | + | |
| 643 | + if (!$valid_sig) { | |
| 644 | + throw new OAuthException("Invalid signature"); | |
| 645 | + } | |
| 646 | + } | |
| 647 | + | |
| 648 | + /** | |
| 649 | + * check that the timestamp is new enough | |
| 650 | + */ | |
| 651 | + private function check_timestamp($timestamp) { | |
| 652 | + if( ! $timestamp ) | |
| 653 | + throw new OAuthException( | |
| 654 | + 'Missing timestamp parameter. The parameter is required' | |
| 655 | + ); | |
| 656 | + | |
| 657 | + // verify that timestamp is recentish | |
| 658 | + $now = time(); | |
| 659 | + if (abs($now - $timestamp) > $this->timestamp_threshold) { | |
| 660 | + throw new OAuthException( | |
| 661 | + "Expired timestamp, yours $timestamp, ours $now" | |
| 662 | + ); | |
| 663 | + } | |
| 664 | + } | |
| 665 | + | |
| 666 | + /** | |
| 667 | + * check that the nonce is not repeated | |
| 668 | + */ | |
| 669 | + private function check_nonce($consumer, $token, $nonce, $timestamp) { | |
| 670 | + if( ! $nonce ) | |
| 671 | + throw new OAuthException( | |
| 672 | + 'Missing nonce parameter. The parameter is required' | |
| 673 | + ); | |
| 674 | + | |
| 675 | + // verify that the nonce is uniqueish | |
| 676 | + $found = $this->data_store->lookup_nonce( | |
| 677 | + $consumer, | |
| 678 | + $token, | |
| 679 | + $nonce, | |
| 680 | + $timestamp | |
| 681 | + ); | |
| 682 | + if ($found) { | |
| 683 | + throw new OAuthException("Nonce already used: $nonce"); | |
| 684 | + } | |
| 685 | + } | |
| 686 | + | |
| 687 | +} | |
| 688 | + | |
| 689 | +class OAuthDataStore { | |
| 690 | + function lookup_consumer($consumer_key) { | |
| 691 | + // implement me | |
| 692 | + } | |
| 693 | + | |
| 694 | + function lookup_token($consumer, $token_type, $token) { | |
| 695 | + // implement me | |
| 696 | + } | |
| 697 | + | |
| 698 | + function lookup_nonce($consumer, $token, $nonce, $timestamp) { | |
| 699 | + // implement me | |
| 700 | + } | |
| 701 | + | |
| 702 | + function new_request_token($consumer, $callback = null) { | |
| 703 | + // return a new token attached to this consumer | |
| 704 | + } | |
| 705 | + | |
| 706 | + function new_access_token($token, $consumer, $verifier = null) { | |
| 707 | + // return a new access token attached to this consumer | |
| 708 | + // for the user associated with this token if the request token | |
| 709 | + // is authorized | |
| 710 | + // should also invalidate the request token | |
| 711 | + } | |
| 712 | + | |
| 713 | +} | |
| 714 | + | |
| 715 | +class OAuthUtil { | |
| 716 | + public static function urlencode_rfc3986($input) { | |
| 717 | + if (is_array($input)) { | |
| 718 | + return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); | |
| 719 | + } else if (is_scalar($input)) { | |
| 720 | + return str_replace( | |
| 721 | + '+', | |
| 722 | + ' ', | |
| 723 | + str_replace('%7E', '~', rawurlencode($input)) | |
| 724 | + ); | |
| 725 | + } else { | |
| 726 | + return ''; | |
| 727 | + } | |
| 728 | +} | |
| 729 | + | |
| 730 | + | |
| 731 | + // This decode function isn't taking into consideration the above | |
| 732 | + // modifications to the encoding process. However, this method doesn't | |
| 733 | + // seem to be used anywhere so leaving it as is. | |
| 734 | + public static function urldecode_rfc3986($string) { | |
| 735 | + return urldecode($string); | |
| 736 | + } | |
| 737 | + | |
| 738 | + // Utility function for turning the Authorization: header into | |
| 739 | + // parameters, has to do some unescaping | |
| 740 | + // Can filter out any non-oauth parameters if needed (default behaviour) | |
| 741 | + public static function split_header($header, $only_allow_oauth_parameters = true) { | |
| 742 | + $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; | |
| 743 | + $offset = 0; | |
| 744 | + $params = array(); | |
| 745 | + while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { | |
| 746 | + $match = $matches[0]; | |
| 747 | + $header_name = $matches[2][0]; | |
| 748 | + $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; | |
| 749 | + if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) { | |
| 750 | + $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content); | |
| 751 | + } | |
| 752 | + $offset = $match[1] + strlen($match[0]); | |
| 753 | + } | |
| 754 | + | |
| 755 | + if (isset($params['realm'])) { | |
| 756 | + unset($params['realm']); | |
| 757 | + } | |
| 758 | + | |
| 759 | + return $params; | |
| 760 | + } | |
| 761 | + | |
| 762 | + // helper to try to sort out headers for people who aren't running apache | |
| 763 | + public static function get_headers() { | |
| 764 | + if (function_exists('apache_request_headers')) { | |
| 765 | + // we need this to get the actual Authorization: header | |
| 766 | + // because apache tends to tell us it doesn't exist | |
| 767 | + $headers = apache_request_headers(); | |
| 768 | + | |
| 769 | + // sanitize the output of apache_request_headers because | |
| 770 | + // we always want the keys to be Cased-Like-This and arh() | |
| 771 | + // returns the headers in the same case as they are in the | |
| 772 | + // request | |
| 773 | + $out = array(); | |
| 774 | + foreach( $headers AS $key => $value ) { | |
| 775 | + $key = str_replace( | |
| 776 | + " ", | |
| 777 | + "-", | |
| 778 | + ucwords(strtolower(str_replace("-", " ", $key))) | |
| 779 | + ); | |
| 780 | + $out[$key] = $value; | |
| 781 | + } | |
| 782 | + } else { | |
| 783 | + // otherwise we don't have apache and are just going to have to hope | |
| 784 | + // that $_SERVER actually contains what we need | |
| 785 | + $out = array(); | |
| 786 | + foreach ($_SERVER as $key => $value) { | |
| 787 | + if (substr($key, 0, 5) == "HTTP_") { | |
| 788 | + // this is chaos, basically it is just there to capitalize the first | |
| 789 | + // letter of every word that is not an initial HTTP and strip HTTP | |
| 790 | + // code from przemek | |
| 791 | + $key = str_replace( | |
| 792 | + " ", | |
| 793 | + "-", | |
| 794 | + ucwords(strtolower(str_replace("_", " ", substr($key, 5)))) | |
| 795 | + ); | |
| 796 | + $out[$key] = $value; | |
| 797 | + } | |
| 798 | + } | |
| 799 | + } | |
| 800 | + return $out; | |
| 801 | + } | |
| 802 | + | |
| 803 | + // This function takes a input like a=b&a=c&d=e and returns the parsed | |
| 804 | + // parameters like this | |
| 805 | + // array('a' => array('b','c'), 'd' => 'e') | |
| 806 | + public static function parse_parameters( $input ) { | |
| 807 | + if (!isset($input) || !$input) return array(); | |
| 808 | + | |
| 809 | + $pairs = explode('&', $input); | |
| 810 | + | |
| 811 | + $parsed_parameters = array(); | |
| 812 | + foreach ($pairs as $pair) { | |
| 813 | + $split = explode('=', $pair, 2); | |
| 814 | + $parameter = OAuthUtil::urldecode_rfc3986($split[0]); | |
| 815 | + $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : ''; | |
| 816 | + | |
| 817 | + if (isset($parsed_parameters[$parameter])) { | |
| 818 | + // We have already recieved parameter(s) with this name, so add to the list | |
| 819 | + // of parameters with this name | |
| 820 | + | |
| 821 | + if (is_scalar($parsed_parameters[$parameter])) { | |
| 822 | + // This is the first duplicate, so transform scalar (string) into an array | |
| 823 | + // so we can add the duplicates | |
| 824 | + $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); | |
| 825 | + } | |
| 826 | + | |
| 827 | + $parsed_parameters[$parameter][] = $value; | |
| 828 | + } else { | |
| 829 | + $parsed_parameters[$parameter] = $value; | |
| 830 | + } | |
| 831 | + } | |
| 832 | + return $parsed_parameters; | |
| 833 | + } | |
| 834 | + | |
| 835 | + public static function build_http_query($params) { | |
| 836 | + if (!$params) return ''; | |
| 837 | + | |
| 838 | + // Urlencode both keys and values | |
| 839 | + $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); | |
| 840 | + $values = OAuthUtil::urlencode_rfc3986(array_values($params)); | |
| 841 | + $params = array_combine($keys, $values); | |
| 842 | + | |
| 843 | + // Parameters are sorted by name, using lexicographical byte value ordering. | |
| 844 | + // Ref: Spec: 9.1.1 (1) | |
| 845 | + uksort($params, 'strcmp'); | |
| 846 | + | |
| 847 | + $pairs = array(); | |
| 848 | + foreach ($params as $parameter => $value) { | |
| 849 | + if (is_array($value)) { | |
| 850 | + // If two or more parameters share the same name, they are sorted by their value | |
| 851 | + // Ref: Spec: 9.1.1 (1) | |
| 852 | + natsort($value); | |
| 853 | + foreach ($value as $duplicate_value) { | |
| 854 | + $pairs[] = $parameter . '=' . $duplicate_value; | |
| 855 | + } | |
| 856 | + } else { | |
| 857 | + $pairs[] = $parameter . '=' . $value; | |
| 858 | + } | |
| 859 | + } | |
| 860 | + // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) | |
| 861 | + // Each name-value pair is separated by an '&' character (ASCII code 38) | |
| 862 | + return implode('&', $pairs); | |
| 863 | + } | |
| 864 | +} | |
| 865 | + | |
| 866 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | +<phpunit colors="true"> | |
| 2 | + <testsuite name="OAuth"> | |
| 3 | + <directory>tests</directory> | |
| 4 | + </testsuite> | |
| 5 | + <filter> | |
| 6 | + <blacklist> | |
| 7 | + <directory>tests</directory> | |
| 8 | + </blacklist> | |
| 9 | + </filter> | |
| 10 | + <logging> | |
| 11 | + <log type="coverage-html" target="./report" charset="UTF-8" yui="true" highlight="false" lowUpperBound="35" highLowerBound="70"/> | |
| 12 | + </logging> | |
| 13 | +</phpunit> | |
| 0 | 14 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,106 @@ |
| 1 | +<?php //vim: foldmethod=marker | |
| 2 | +//require_once("OAuth.php"); | |
| 3 | + | |
| 4 | +class TestOAuthServer extends OAuthServer { | |
| 5 | + public function get_signature_methods() { | |
| 6 | + return $this->signature_methods; | |
| 7 | + } | |
| 8 | +} | |
| 9 | + | |
| 10 | +class TestOAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod_RSA_SHA1 { | |
| 11 | + public function fetch_private_cert(&$request) { | |
| 12 | + $cert = <<<EOD | |
| 13 | +-----BEGIN PRIVATE KEY----- | |
| 14 | +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V | |
| 15 | +A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d | |
| 16 | +7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ | |
| 17 | +hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H | |
| 18 | +X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm | |
| 19 | +uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw | |
| 20 | +rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z | |
| 21 | +zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn | |
| 22 | +qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG | |
| 23 | +WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno | |
| 24 | +cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+ | |
| 25 | +3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8 | |
| 26 | +AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54 | |
| 27 | +Lw03eHTNQghS0A== | |
| 28 | +-----END PRIVATE KEY----- | |
| 29 | +EOD; | |
| 30 | + return $cert; | |
| 31 | + } | |
| 32 | + | |
| 33 | + public function fetch_public_cert(&$request) { | |
| 34 | + $cert = <<<EOD | |
| 35 | +-----BEGIN CERTIFICATE----- | |
| 36 | +MIIBpjCCAQ+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAZMRcwFQYDVQQDDA5UZXN0 | |
| 37 | +IFByaW5jaXBhbDAeFw03MDAxMDEwODAwMDBaFw0zODEyMzEwODAwMDBaMBkxFzAV | |
| 38 | +BgNVBAMMDlRlc3QgUHJpbmNpcGFsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB | |
| 39 | +gQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlY | |
| 40 | +zypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp/IpH7kH41Etb | |
| 41 | +mUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQABMA0GCSqGSIb3 | |
| 42 | +DQEBBQUAA4GBAGZLPEuJ5SiJ2ryq+CmEGOXfvlTtEL2nuGtr9PewxkgnOjZpUy+d | |
| 43 | +4TvuXJbNQc8f4AMWL/tO9w0Fk80rWKp9ea8/df4qMq5qlFWlx6yOLQxumNOmECKb | |
| 44 | +WpkUQDIDJEoFUzKMVuJf4KO/FJ345+BNLGgbJ6WujreoM1X/gYfdnJ/J | |
| 45 | +-----END CERTIFICATE----- | |
| 46 | +EOD; | |
| 47 | + return $cert; | |
| 48 | + } | |
| 49 | +} | |
| 50 | + | |
| 51 | +/** | |
| 52 | + * A mock store for testing | |
| 53 | + */ | |
| 54 | +class MockOAuthDataStore extends OAuthDataStore {/*{{{*/ | |
| 55 | + private $consumer; | |
| 56 | + private $request_token; | |
| 57 | + private $access_token; | |
| 58 | + private $nonce; | |
| 59 | + | |
| 60 | + function __construct() {/*{{{*/ | |
| 61 | + $this->consumer = new OAuthConsumer("key", "secret", NULL); | |
| 62 | + $this->request_token = new OAuthToken("requestkey", "requestsecret", 1); | |
| 63 | + $this->access_token = new OAuthToken("accesskey", "accesssecret", 1); | |
| 64 | + $this->nonce = "nonce"; | |
| 65 | + }/*}}}*/ | |
| 66 | + | |
| 67 | + function lookup_consumer($consumer_key) {/*{{{*/ | |
| 68 | + if ($consumer_key == $this->consumer->key) return $this->consumer; | |
| 69 | + return NULL; | |
| 70 | + }/*}}}*/ | |
| 71 | + | |
| 72 | + function lookup_token($consumer, $token_type, $token) {/*{{{*/ | |
| 73 | + $token_attrib = $token_type . "_token"; | |
| 74 | + if ($consumer->key == $this->consumer->key | |
| 75 | + && $token == $this->$token_attrib->key) { | |
| 76 | + return $this->$token_attrib; | |
| 77 | + } | |
| 78 | + return NULL; | |
| 79 | + }/*}}}*/ | |
| 80 | + | |
| 81 | + function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/ | |
| 82 | + if ($consumer->key == $this->consumer->key | |
| 83 | + && (($token && $token->key == $this->request_token->key) | |
| 84 | + || ($token && $token->key == $this->access_token->key)) | |
| 85 | + && $nonce == $this->nonce) { | |
| 86 | + return $this->nonce; | |
| 87 | + } | |
| 88 | + return NULL; | |
| 89 | + }/*}}}*/ | |
| 90 | + | |
| 91 | + function new_request_token($consumer) {/*{{{*/ | |
| 92 | + if ($consumer->key == $this->consumer->key) { | |
| 93 | + return $this->request_token; | |
| 94 | + } | |
| 95 | + return NULL; | |
| 96 | + }/*}}}*/ | |
| 97 | + | |
| 98 | + function new_access_token($token, $consumer) {/*{{{*/ | |
| 99 | + if ($consumer->key == $this->consumer->key | |
| 100 | + && $token->key == $this->request_token->key) { | |
| 101 | + return $this->access_token; | |
| 102 | + } | |
| 103 | + return NULL; | |
| 104 | + }/*}}}*/ | |
| 105 | +}/*}}}*/ | |
| 106 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,68 @@ |
| 1 | +Interfaces: | |
| 2 | + | |
| 3 | +# OAuthConsumer is a data type that represents the identity of the Consumer | |
| 4 | +# via its shared secret with the Service Provider. | |
| 5 | +OAuthConsumer | |
| 6 | + - key : str | |
| 7 | + - secret : str | |
| 8 | + | |
| 9 | +# OAuthToken is a data type that represents an End User via either an access | |
| 10 | +# or request token | |
| 11 | +OAuthToken | |
| 12 | + - token : str | |
| 13 | + - secret : str | |
| 14 | + - to_string() -> str | |
| 15 | + - (static) from_string() -> OAuthToken | |
| 16 | + | |
| 17 | +# OAuthSignatureMethod is a strategy class that implements a signature method | |
| 18 | +OAuthSignatureMethod | |
| 19 | + - get_name() -> str | |
| 20 | + - build_signature (OAuthRequest, OAuthConsumer, OAuthToken) -> str | |
| 21 | + | |
| 22 | +# OAuthRequest represents the request and can be seriali | |
| 23 | +OAuthRequest: | |
| 24 | + - OAuthRequest(str http_method, str http_url, [dict parameters]) -> constructor | |
| 25 | + - set_parameter(str parameter, str value) -> void | |
| 26 | + - example parameters: oauth_consumer_key, foo | |
| 27 | + - get_parameter(str parameter) -> str | |
| 28 | + - get_parameters() -> dict | |
| 29 | + | |
| 30 | + - get_normalized_http_method() -> str | |
| 31 | + - get_normalized_http_url() -> str | |
| 32 | + - get_signable_params() -> dict | |
| 33 | + | |
| 34 | + - to_header () -> str # serialize as a header for an HTTPAuth request | |
| 35 | + - to_postdata () -> str # serialize as post data for a POST request | |
| 36 | + - to_url () -> str # serialize as a url for a GET request | |
| 37 | + - sign_request(OAuthSignatureMethod, OAuthConsumer, OAuthToken) -> void | |
| 38 | + - build_signature(OAuthSignatureMethod, OAuthConsumer, OAuthToken) -> str | |
| 39 | + - (static) from_request([str http_method, str http_url, dict parameters]) | |
| 40 | + - (static) from_consumer_and_token(OAuthConsumer, OAuthToken, str http_method, str http_url, [dict parameters]) -> OAuthRequest | |
| 41 | + | |
| 42 | + | |
| 43 | +# OAuthServer is a worker to check a requests validity against a data store | |
| 44 | +OAuthServer: | |
| 45 | + - OAuthServer(OAuthDataStore) -> constructor | |
| 46 | + - set_data_store(OAuthDataStore) -> void | |
| 47 | + - get_data_store() -> OAuthDataStore | |
| 48 | + | |
| 49 | + - fetch_request_token (OAuthRequest) -> OAuthToken | |
| 50 | + - fetch_access_token (OAuthRequest) -> OAuthToken | |
| 51 | + - verify_request (OAuthRequest) -> OAuthToken | |
| 52 | + | |
| 53 | +# OAuthClient is a worker to attempt to execute a request | |
| 54 | +OAuthClient: | |
| 55 | + - OAuthClient(OAuthConsumer, OAuthToken) -> constructor | |
| 56 | + - get_consumer() -> OAuthConsumer | |
| 57 | + - get_token() -> OAuthToken | |
| 58 | + | |
| 59 | + - fetch_request_token (OAuthRequest) -> OAuthToken | |
| 60 | + - fetch_access_token (OAuthRequest) -> OAuthToken | |
| 61 | + | |
| 62 | +# OAuthDataStore is a database abstraction used to lookup consumers and tokens | |
| 63 | +OAuthDataStore: | |
| 64 | + - lookup_consumer(str key) -> OAuthConsumer | |
| 65 | + - lookup_token(OAuthConsumer, str token_type, str token_token) -> OAuthToken | |
| 66 | + - lookup_nonce(OAuthConsumer, OAuthToken, str nonce, int timestamp) -> OAuthToken | |
| 67 | + - fetch_request_token(OAuthConsumer) -> OAuthToken | |
| 68 | + - fetch_access_token(OAuthConsumer, OAuthToken) -> OAuthToken | ... | ... |
| ... | ... | @@ -0,0 +1,74 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/* A very naive dbm-based oauth storage | |
| 4 | + * | |
| 5 | + * NOTE: This is for reference ONLY, | |
| 6 | + * and contains, amongst others, a hole | |
| 7 | + * where you can get the token secret | |
| 8 | + * easily.. | |
| 9 | + */ | |
| 10 | +class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/ | |
| 11 | + private $dbh; | |
| 12 | + | |
| 13 | + function __construct($path = "oauth.gdbm") {/*{{{*/ | |
| 14 | + $this->dbh = dba_popen($path, 'c', 'gdbm'); | |
| 15 | + }/*}}}*/ | |
| 16 | + | |
| 17 | + function __destruct() {/*{{{*/ | |
| 18 | + dba_close($this->dbh); | |
| 19 | + }/*}}}*/ | |
| 20 | + | |
| 21 | + function lookup_consumer($consumer_key) {/*{{{*/ | |
| 22 | + $rv = dba_fetch("consumer_$consumer_key", $this->dbh); | |
| 23 | + if ($rv === FALSE) { | |
| 24 | + return NULL; | |
| 25 | + } | |
| 26 | + $obj = unserialize($rv); | |
| 27 | + if (!($obj instanceof OAuthConsumer)) { | |
| 28 | + return NULL; | |
| 29 | + } | |
| 30 | + return $obj; | |
| 31 | + }/*}}}*/ | |
| 32 | + | |
| 33 | + function lookup_token($consumer, $token_type, $token) {/*{{{*/ | |
| 34 | + $rv = dba_fetch("${token_type}_${token}", $this->dbh); | |
| 35 | + if ($rv === FALSE) { | |
| 36 | + return NULL; | |
| 37 | + } | |
| 38 | + $obj = unserialize($rv); | |
| 39 | + if (!($obj instanceof OAuthToken)) { | |
| 40 | + return NULL; | |
| 41 | + } | |
| 42 | + return $obj; | |
| 43 | + }/*}}}*/ | |
| 44 | + | |
| 45 | + function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/ | |
| 46 | + if (dba_exists("nonce_$nonce", $this->dbh)) { | |
| 47 | + return TRUE; | |
| 48 | + } else { | |
| 49 | + dba_insert("nonce_$nonce", "1", $this->dbh); | |
| 50 | + return FALSE; | |
| 51 | + } | |
| 52 | + }/*}}}*/ | |
| 53 | + | |
| 54 | + function new_token($consumer, $type="request") {/*{{{*/ | |
| 55 | + $key = md5(time()); | |
| 56 | + $secret = time() + time(); | |
| 57 | + $token = new OAuthToken($key, md5(md5($secret))); | |
| 58 | + if (!dba_insert("${type}_$key", serialize($token), $this->dbh)) { | |
| 59 | + throw new OAuthException("doooom!"); | |
| 60 | + } | |
| 61 | + return $token; | |
| 62 | + }/*}}}*/ | |
| 63 | + | |
| 64 | + function new_request_token($consumer) {/*{{{*/ | |
| 65 | + return $this->new_token($consumer, "request"); | |
| 66 | + }/*}}}*/ | |
| 67 | + | |
| 68 | + function new_access_token($token, $consumer) {/*{{{*/ | |
| 69 | + | |
| 70 | + $token = $this->new_token($consumer, 'access'); | |
| 71 | + dba_delete("request_" . $token->key, $this->dbh); | |
| 72 | + return $token; | |
| 73 | + }/*}}}*/ | |
| 74 | +}/*}}}*/ | |
| 0 | 75 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +<?php | |
| 2 | +require_once("common.inc.php"); | |
| 3 | + | |
| 4 | +try { | |
| 5 | + $req = OAuthRequest::from_request(); | |
| 6 | + $token = $test_server->fetch_access_token($req); | |
| 7 | + print $token; | |
| 8 | +} catch (OAuthException $e) { | |
| 9 | + print($e->getMessage() . "\n<hr />\n"); | |
| 10 | + print_r($req); | |
| 11 | + die(); | |
| 12 | +} | |
| 13 | + | |
| 14 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,133 @@ |
| 1 | +<?php | |
| 2 | +require_once("common.inc.php"); | |
| 3 | + | |
| 4 | +$key = @$_REQUEST['key']; | |
| 5 | +$secret = @$_REQUEST['secret']; | |
| 6 | +$token = @$_REQUEST['token']; | |
| 7 | +$token_secret = @$_REQUEST['token_secret']; | |
| 8 | +$endpoint = @$_REQUEST['endpoint']; | |
| 9 | +$action = @$_REQUEST['action']; | |
| 10 | +$dump_request = @$_REQUEST['dump_request']; | |
| 11 | +$user_sig_method = @$_REQUEST['sig_method']; | |
| 12 | +$sig_method = $hmac_method; | |
| 13 | +if ($user_sig_method) { | |
| 14 | + $sig_method = $sig_methods[$user_sig_method]; | |
| 15 | +} | |
| 16 | + | |
| 17 | +$test_consumer = new OAuthConsumer($key, $secret, NULL); | |
| 18 | + | |
| 19 | +$test_token = NULL; | |
| 20 | +if ($token) { | |
| 21 | + $test_token = new OAuthConsumer($token, $token_secret); | |
| 22 | +} | |
| 23 | + | |
| 24 | + | |
| 25 | +if ($action == "request_token") { | |
| 26 | + $parsed = parse_url($endpoint); | |
| 27 | + $params = array(); | |
| 28 | + parse_str($parsed['query'], $params); | |
| 29 | + | |
| 30 | + $req_req = OAuthRequest::from_consumer_and_token($test_consumer, NULL, "GET", $endpoint, $params); | |
| 31 | + $req_req->sign_request($sig_method, $test_consumer, NULL); | |
| 32 | + if ($dump_request) { | |
| 33 | + Header('Content-type: text/plain'); | |
| 34 | + print "request url: " . $req_req->to_url(). "\n"; | |
| 35 | + print_r($req_req); | |
| 36 | + exit; | |
| 37 | + } | |
| 38 | + Header("Location: $req_req"); | |
| 39 | +} | |
| 40 | +else if ($action == "authorize") { | |
| 41 | + $callback_url = "$base_url/client.php?key=$key&secret=$secret&token=$token&token_secret=$token_secret&endpoint=" . urlencode($endpoint); | |
| 42 | + $auth_url = $endpoint . "?oauth_token=$token&oauth_callback=".urlencode($callback_url); | |
| 43 | + if ($dump_request) { | |
| 44 | + Header('Content-type: text/plain'); | |
| 45 | + print("auth_url: " . $auth_url); | |
| 46 | + exit; | |
| 47 | + } | |
| 48 | + Header("Location: $auth_url"); | |
| 49 | +} | |
| 50 | +else if ($action == "access_token") { | |
| 51 | + $parsed = parse_url($endpoint); | |
| 52 | + $params = array(); | |
| 53 | + parse_str($parsed['query'], $params); | |
| 54 | + | |
| 55 | + $acc_req = OAuthRequest::from_consumer_and_token($test_consumer, $test_token, "GET", $endpoint, $params); | |
| 56 | + $acc_req->sign_request($sig_method, $test_consumer, $test_token); | |
| 57 | + if ($dump_request) { | |
| 58 | + Header('Content-type: text/plain'); | |
| 59 | + print "request url: " . $acc_req->to_url() . "\n"; | |
| 60 | + print_r($acc_req); | |
| 61 | + exit; | |
| 62 | + } | |
| 63 | + Header("Location: $acc_req"); | |
| 64 | +} | |
| 65 | + | |
| 66 | +?> | |
| 67 | +<html> | |
| 68 | +<head> | |
| 69 | +<title>OAuth Test Client</title> | |
| 70 | +</head> | |
| 71 | +<body> | |
| 72 | +<div><a href="index.php">server</a> | <a href="client.php">client</a></div> | |
| 73 | +<h1>OAuth Test Client</h1> | |
| 74 | +<h2>Instructions for Use</h2> | |
| 75 | +<p>This is a test client that will let you test your OAuth server code. Enter the appropriate information below to test.</p> | |
| 76 | +<p>Note: we don't store any of the information you type in.</p> | |
| 77 | + | |
| 78 | +<form method="POST" name="oauth_client"> | |
| 79 | +<h3>Choose a Signature Method</h3> | |
| 80 | +<select name="sig_method"> | |
| 81 | +<?php | |
| 82 | +foreach ($sig_methods as $name=> $method) { | |
| 83 | + $selected = ""; | |
| 84 | + if ($name == $sig_method->get_name()) { | |
| 85 | + $selected = " selected='selected'"; | |
| 86 | + } | |
| 87 | + print "<option value='$name'$selected>$name</option>\n"; | |
| 88 | +} | |
| 89 | +?> | |
| 90 | +</select> | |
| 91 | +<h3>Enter The Endpoint to Test</h3> | |
| 92 | +endpoint: <input type="text" name="endpoint" value="<?php echo $endpoint; ?>" size="100"/><br /> | |
| 93 | +<small style="color: green">Note: You can include query parameters in there to have them parsed in and signed too</small> | |
| 94 | +<h3>Enter Your Consumer Key / Secret</h3> | |
| 95 | +consumer key: <input type="text" name="key" value="<?php echo $key; ?>" /><br /> | |
| 96 | +consumer secret: <input type="text" name="secret" value="<?php echo $secret;?>" /><br /> | |
| 97 | +dump request, don't redirect: <input type="checkbox" name="dump_request" value="1" <?php if ($dump_request) echo 'checked="checked"'; ?>/><br /> | |
| 98 | +make a token request (don't forget to copy down the values you get) | |
| 99 | +<input type="submit" name="action" value="request_token" /> | |
| 100 | +<h3>Enter Your Request Token / Secret</h3> | |
| 101 | +token: <input type="text" name="token" value="<?php echo $token; ?>" /><br /> | |
| 102 | +token secret: <input type="text" name="token_secret" value="<?php echo $token_secret; ?>" /><br /> | |
| 103 | +<p><strong>Don't forget to update your endpoint to point at the auth or access token url</strong></p> | |
| 104 | +try to authorize this token: <input type="submit" name="action" value="authorize" /><br /> | |
| 105 | +try to get an access token: <input type="submit" name="action" value="access_token" /><br /> | |
| 106 | + | |
| 107 | +<h3>Currently Supported Signature Methods</h3> | |
| 108 | +<p>Current signing method is: <?php echo $sig_method->get_name() ?></p> | |
| 109 | +<ul> | |
| 110 | +<?php | |
| 111 | +foreach ($sig_methods as $key => $method) { | |
| 112 | + | |
| 113 | + print "<li>$key"; | |
| 114 | + if ($key != $sig_method->get_name()) { | |
| 115 | + print "(<a href='?sig_method=$key'>switch</a>)"; | |
| 116 | + } | |
| 117 | + print "</li>\n"; | |
| 118 | +} | |
| 119 | +?> | |
| 120 | +</ul> | |
| 121 | + | |
| 122 | +<?php | |
| 123 | +if ("RSA-SHA1" == $sig_method->get_name()) { | |
| 124 | + // passing test_server as a dummy referecne | |
| 125 | + print "<pre>" . $sig_method->fetch_private_cert($test_server). "</pre>\n"; | |
| 126 | + print "<pre>" . $sig_method->fetch_public_cert($test_server) . "</pre>\n"; | |
| 127 | +} | |
| 128 | +?> | |
| 129 | + | |
| 130 | +<h3>Further Resources</h3> | |
| 131 | +<p>There is also a <a href="index.php">test server</a> implementation in here.</p> | |
| 132 | +<p>The code running this example can be downloaded from the PHP section of the OAuth google code project: <a href="http://code.google.com/p/oauth/">http://code.google.com/p/oauth/</a> | |
| 133 | +</body> | ... | ... |
| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | +<?php | |
| 2 | +require_once("../OAuth.php"); | |
| 3 | +require_once("../OAuth_TestServer.php"); | |
| 4 | + | |
| 5 | +/* | |
| 6 | + * Config Section | |
| 7 | + */ | |
| 8 | +$domain = $_SERVER['HTTP_HOST']; | |
| 9 | +$base = "/i3geo/pacotes/linkedinoauth/example"; | |
| 10 | + | |
| 11 | +$base_url = "http://$domain$base"; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * Some default objects | |
| 15 | + */ | |
| 16 | + | |
| 17 | +$test_server = new TestOAuthServer(new MockOAuthDataStore()); | |
| 18 | +$hmac_method = new OAuthSignatureMethod_HMAC_SHA1(); | |
| 19 | +$plaintext_method = new OAuthSignatureMethod_PLAINTEXT(); | |
| 20 | +$rsa_method = new TestOAuthSignatureMethod_RSA_SHA1(); | |
| 21 | + | |
| 22 | +$test_server->add_signature_method($hmac_method); | |
| 23 | +$test_server->add_signature_method($plaintext_method); | |
| 24 | +$test_server->add_signature_method($rsa_method); | |
| 25 | + | |
| 26 | +$sig_methods = $test_server->get_signature_methods(); | |
| 27 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +<?php | |
| 2 | +require_once("common.inc.php"); | |
| 3 | + | |
| 4 | +try { | |
| 5 | + $req = OAuthRequest::from_request(); | |
| 6 | + list($consumer, $token) = $test_server->verify_request($req); | |
| 7 | + | |
| 8 | + // lsit back the non-OAuth params | |
| 9 | + $total = array(); | |
| 10 | + foreach($req->get_parameters() as $k => $v) { | |
| 11 | + if (substr($k, 0, 5) == "oauth") continue; | |
| 12 | + $total[] = urlencode($k) . "=" . urlencode($v); | |
| 13 | + } | |
| 14 | + print implode("&", $total); | |
| 15 | +} catch (OAuthException $e) { | |
| 16 | + print($e->getMessage() . "\n<hr />\n"); | |
| 17 | + print_r($req); | |
| 18 | + die(); | |
| 19 | +} | |
| 20 | + | |
| 21 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,108 @@ |
| 1 | +<?php | |
| 2 | +require_once("common.inc.php"); | |
| 3 | +include_once("../../../ms_configura.php"); | |
| 4 | + | |
| 5 | +$test_consumer = new OAuthConsumer($linkedinoauth["consumerkey"], $linkedinoauth["consumersecret"], NULL); | |
| 6 | +$req_token = new OAuthConsumer($linkedinoauth["consumerkey"], $linkedinoauth["consumersecret"], 1); | |
| 7 | +$acc_token = new OAuthConsumer($linkedinoauth["consumerkey"], $linkedinoauth["consumersecret"], 1); | |
| 8 | + | |
| 9 | +$sig_method = $hmac_method; | |
| 10 | +$user_sig_method = @$_GET['sig_method']; | |
| 11 | +if ($user_sig_method) { | |
| 12 | + $sig_method = $sig_methods[$user_sig_method]; | |
| 13 | +} | |
| 14 | + | |
| 15 | +$req_req = OAuthRequest::from_consumer_and_token($test_consumer, NULL, "GET", $base_url . "/request_token.php"); | |
| 16 | +$req_req->sign_request($sig_method, $test_consumer, NULL); | |
| 17 | + | |
| 18 | +$acc_req = OAuthRequest::from_consumer_and_token($test_consumer, $req_token, "GET", $base_url . "/access_token.php"); | |
| 19 | +$acc_req->sign_request($sig_method, $test_consumer, $req_token); | |
| 20 | + | |
| 21 | +$echo_req = OAuthRequest::from_consumer_and_token($test_consumer, $acc_token, "GET", $base_url . "/echo_api.php", array("method"=> "foo%20bar", "bar" => "baz")); | |
| 22 | +$echo_req->sign_request($sig_method, $test_consumer, $acc_token); | |
| 23 | + | |
| 24 | +?> | |
| 25 | +<html> | |
| 26 | +<head> | |
| 27 | +<title>OAuth Test Server</title> | |
| 28 | +</head> | |
| 29 | +<body> | |
| 30 | +<div><a href="index.php">server</a> | <a href="client.php">client</a></div> | |
| 31 | +<h1>OAuth Test Server</h1> | |
| 32 | +<h2>Instructions for Use</h2> | |
| 33 | +<p>This is a test server with a predefined static set of keys and tokens, you can make your requests using them to test your code (and mine ;)).</p> | |
| 34 | +<h3>Your Consumer Key / Secret</h3> | |
| 35 | +<ul> | |
| 36 | +<li>consumer key: <code><strong>key</strong></code></li> | |
| 37 | +<li>consumer secret: <code><strong>secret</strong></code></li> | |
| 38 | +</ul> | |
| 39 | +<p>Use this key and secret for all your requests.</p> | |
| 40 | +<h3>Getting a Request Token</h3> | |
| 41 | + | |
| 42 | +<ul> | |
| 43 | +<li>request token endpoint: <code><strong><?php echo $base_url . "/request_token.php"; ?></strong></code></li> | |
| 44 | +</ul> | |
| 45 | + | |
| 46 | +<p>A successful request will return the following:</p> | |
| 47 | +<p><code>oauth_token=requestkey&oauth_token_secret=requestsecret</code></p> | |
| 48 | + | |
| 49 | +<p>An unsuccessful request will attempt to describe what went wrong.</p> | |
| 50 | + | |
| 51 | +<h4>Example</h4> | |
| 52 | +<a href="<?php echo $req_req; ?>"><?php echo $req_req; ?></a> | |
| 53 | + | |
| 54 | +<h3>Getting an Access Token</h3> | |
| 55 | +<p>The Request Token provided above is already authorized, you may use it to request an Access Token right away.</p> | |
| 56 | + | |
| 57 | +<ul> | |
| 58 | +<li>access token endpoint: <code><strong><?php echo $base_url . "/access_token.php"; ?></strong></code></li> | |
| 59 | +</ul> | |
| 60 | + | |
| 61 | +<p>A successful request will return the following:</p> | |
| 62 | +<p><code>oauth_token=accesskey&oauth_token_secret=accesssecret</code></p> | |
| 63 | + | |
| 64 | +<p>An unsuccessful request will attempt to describe what went wrong.</p> | |
| 65 | + | |
| 66 | +<h4>Example</h4> | |
| 67 | +<a href="<?php echo $acc_req; ?>"><?php echo $acc_req; ?></a> | |
| 68 | + | |
| 69 | +<h3>Making Authenticated Calls</h3> | |
| 70 | +<p>Using your Access Token you can make authenticated calls.</p> | |
| 71 | + | |
| 72 | +<ul> | |
| 73 | +<li>api endpoint: <code><strong><?php echo $base_url . "/echo_api.php"; ?></strong></code></li> | |
| 74 | +</ul> | |
| 75 | +<p> | |
| 76 | +A successful request will echo the non-OAuth parameters sent to it, for example:</p> | |
| 77 | +<p><code>method=foo&bar=baz</code></p> | |
| 78 | +<p>An unsuccessful request will attempt to describe what went wrong.</p> | |
| 79 | + | |
| 80 | +<h4>Example</h4> | |
| 81 | +<a href="<?php echo $echo_req; ?>"><?php echo $echo_req; ?></a> | |
| 82 | + | |
| 83 | +<h3>Currently Supported Signature Methods</h3> | |
| 84 | +<p>Current signing method is: <?php echo $user_sig_method ?></p> | |
| 85 | +<ul> | |
| 86 | +<?php | |
| 87 | +$sig_methods = $test_server->get_signature_methods(); | |
| 88 | +foreach ($sig_methods as $key => $method) { | |
| 89 | + print "<li>$key"; | |
| 90 | + if ($key != $sig_method->get_name()) { | |
| 91 | + print "(<a href='?sig_method=$key'>switch</a>)"; | |
| 92 | + } | |
| 93 | + print "</li>\n"; | |
| 94 | +} | |
| 95 | +?> | |
| 96 | +</ul> | |
| 97 | + | |
| 98 | +<?php | |
| 99 | +if ("RSA-SHA1" == $sig_method->get_name()) { | |
| 100 | + print "<pre>" . $sig_method->fetch_private_cert($req_req) . "</pre>\n"; | |
| 101 | + print "<pre>" . $sig_method->fetch_public_cert($req_req) . "</pre>\n"; | |
| 102 | +} | |
| 103 | +?> | |
| 104 | + | |
| 105 | +<h3>Further Resources</h3> | |
| 106 | +<p>There is also a <a href="client.php">test client</a> implementation in here.</p> | |
| 107 | +<p>The code running this example can be downloaded from the PHP section of the OAuth google code project: <a href="http://code.google.com/p/oauth/">http://code.google.com/p/oauth/</a> | |
| 108 | +</body> | ... | ... |
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | +<?php | |
| 2 | +require_once("common.inc.php"); | |
| 3 | + | |
| 4 | +try { | |
| 5 | + $req = OAuthRequest::from_request(); | |
| 6 | + $token = $test_server->fetch_request_token($req); | |
| 7 | + print $token; | |
| 8 | +} catch (OAuthException $e) { | |
| 9 | + print($e->getMessage() . "\n<hr />\n"); | |
| 10 | + print_r($req); | |
| 11 | + die(); | |
| 12 | +} | |
| 13 | + | |
| 14 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,139 @@ |
| 1 | +<?php | |
| 2 | +require_once("OAuth.php"); | |
| 3 | + | |
| 4 | +class LinkedIn { | |
| 5 | + public $base_url = "http://api.linkedin.com"; | |
| 6 | + public $secure_base_url = "https://api.linkedin.com"; | |
| 7 | + public $oauth_callback = "oob"; | |
| 8 | + public $consumer; | |
| 9 | + public $request_token; | |
| 10 | + public $access_token; | |
| 11 | + public $oauth_verifier; | |
| 12 | + public $signature_method; | |
| 13 | + public $request_token_path; | |
| 14 | + public $access_token_path; | |
| 15 | + public $authorize_path; | |
| 16 | + public $debug = false; | |
| 17 | + | |
| 18 | + function __construct($consumer_key, $consumer_secret, $oauth_callback = NULL) { | |
| 19 | + | |
| 20 | + if($oauth_callback) { | |
| 21 | + $this->oauth_callback = $oauth_callback; | |
| 22 | + } | |
| 23 | + | |
| 24 | + $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret, $this->oauth_callback); | |
| 25 | + $this->signature_method = new OAuthSignatureMethod_HMAC_SHA1(); | |
| 26 | + $this->request_token_path = $this->secure_base_url . "/uas/oauth/requestToken"; | |
| 27 | + $this->access_token_path = $this->secure_base_url . "/uas/oauth/accessToken"; | |
| 28 | + $this->authorize_path = $this->secure_base_url . "/uas/oauth/authorize"; | |
| 29 | + | |
| 30 | + } | |
| 31 | + | |
| 32 | + function getRequestToken() { | |
| 33 | + $consumer = $this->consumer; | |
| 34 | + $request = OAuthRequest::from_consumer_and_token($consumer, NULL, "GET", $this->request_token_path); | |
| 35 | + $request->set_parameter("oauth_callback", $this->oauth_callback); | |
| 36 | + $request->sign_request($this->signature_method, $consumer, NULL); | |
| 37 | + $headers = Array(); | |
| 38 | + $url = $request->to_url(); | |
| 39 | + $response = $this->httpRequest($url, $headers, "GET"); | |
| 40 | + parse_str($response, $response_params); | |
| 41 | + $this->request_token = new OAuthConsumer($response_params['oauth_token'], $response_params['oauth_token_secret'], 1); | |
| 42 | + } | |
| 43 | + | |
| 44 | + function generateAuthorizeUrl() { | |
| 45 | + $consumer = $this->consumer; | |
| 46 | + $request_token = $this->request_token; | |
| 47 | + return $this->authorize_path . "?oauth_token=" . $request_token->key; | |
| 48 | + } | |
| 49 | + | |
| 50 | + function getAccessToken($oauth_verifier) { | |
| 51 | + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->request_token, "GET", $this->access_token_path); | |
| 52 | + $request->set_parameter("oauth_verifier", $oauth_verifier); | |
| 53 | + $request->sign_request($this->signature_method, $this->consumer, $this->request_token); | |
| 54 | + $headers = Array(); | |
| 55 | + $url = $request->to_url(); | |
| 56 | + $response = $this->httpRequest($url, $headers, "GET"); | |
| 57 | + parse_str($response, $response_params); | |
| 58 | + if($debug) { | |
| 59 | + echo $response . "\n"; | |
| 60 | + } | |
| 61 | + $this->access_token = new OAuthConsumer($response_params['oauth_token'], $response_params['oauth_token_secret'], 1); | |
| 62 | + } | |
| 63 | + | |
| 64 | + function getProfile($resource = "~") { | |
| 65 | + $profile_url = $this->base_url . "/v1/people/" . $resource; | |
| 66 | + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->access_token, "GET", $profile_url); | |
| 67 | + $request->sign_request($this->signature_method, $this->consumer, $this->access_token); | |
| 68 | + $auth_header = $request->to_header("https://api.linkedin.com"); # this is the realm | |
| 69 | + # This PHP library doesn't generate the header correctly when a realm is not specified. | |
| 70 | + # Make sure there is a space and not a comma after OAuth | |
| 71 | + // $auth_header = preg_replace("/Authorization\: OAuth\,/", "Authorization: OAuth ", $auth_header); | |
| 72 | + // # Make sure there is a space between OAuth attribute | |
| 73 | + // $auth_header = preg_replace('/\"\,/', '", ', $auth_header); | |
| 74 | + if ($debug) { | |
| 75 | + echo $auth_header; | |
| 76 | + } | |
| 77 | + // $response will now hold the XML document | |
| 78 | + $response = $this->httpRequest($profile_url, $auth_header, "GET"); | |
| 79 | + return $response; | |
| 80 | + } | |
| 81 | + | |
| 82 | + function setStatus($status) { | |
| 83 | + $status_url = $this->base_url . "/v1/people/~/current-status"; | |
| 84 | + echo "Setting status...\n"; | |
| 85 | + $xml = "<current-status>" . htmlspecialchars($status, ENT_NOQUOTES, "UTF-8") . "</current-status>"; | |
| 86 | + echo $xml . "\n"; | |
| 87 | + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->access_token, "PUT", $status_url); | |
| 88 | + $request->sign_request($this->signature_method, $this->consumer, $this->access_token); | |
| 89 | + $auth_header = $request->to_header("https://api.linkedin.com"); | |
| 90 | + if ($debug) { | |
| 91 | + echo $auth_header . "\n"; | |
| 92 | + } | |
| 93 | + $response = $this->httpRequest($profile_url, $auth_header, "GET"); | |
| 94 | + return $response; | |
| 95 | + } | |
| 96 | + | |
| 97 | + # Parameters should be a query string starting with "?" | |
| 98 | + # Example search("?count=10&start=10&company=LinkedIn"); | |
| 99 | + function search($parameters) { | |
| 100 | + $search_url = $this->base_url . "/v1/people/" . $parameters; | |
| 101 | + echo "Performing search for: " . $parameters . "\n"; | |
| 102 | + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->access_token, "GET", $search_url); | |
| 103 | + $request->sign_request($this->signature_method, $this->consumer, $this->access_token); | |
| 104 | + $auth_header = $request->to_header("https://api.linkedin.com"); | |
| 105 | + if ($debug) { | |
| 106 | + echo $request->get_signature_base_string() . "\n"; | |
| 107 | + echo $auth_header . "\n"; | |
| 108 | + } | |
| 109 | + $response = $this->httpRequest($search_url, $auth_header, "GET"); | |
| 110 | + return $response; | |
| 111 | + } | |
| 112 | + | |
| 113 | + function httpRequest($url, $auth_header, $method, $body = NULL) { | |
| 114 | + if (!$method) { | |
| 115 | + $method = "GET"; | |
| 116 | + }; | |
| 117 | + | |
| 118 | + $curl = curl_init(); | |
| 119 | + curl_setopt($curl, CURLOPT_URL, $url); | |
| 120 | + curl_setopt($curl, CURLOPT_HEADER, 0); | |
| 121 | + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); | |
| 122 | + curl_setopt($curl, CURLOPT_HTTPHEADER, array($auth_header)); // Set the headers. | |
| 123 | + | |
| 124 | + if ($body) { | |
| 125 | + curl_setopt($curl, CURLOPT_POST, 1); | |
| 126 | + curl_setopt($curl, CURLOPT_POSTFIELDS, $body); | |
| 127 | + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); | |
| 128 | + curl_setopt($curl, CURLOPT_HTTPHEADER, array($auth_header, "Content-Type: text/xml;charset=utf-8")); | |
| 129 | + } | |
| 130 | + | |
| 131 | + $data = curl_exec($curl); | |
| 132 | + if ($this->debug) { | |
| 133 | + echo $data . "\n"; | |
| 134 | + } | |
| 135 | + curl_close($curl); | |
| 136 | + return $data; | |
| 137 | + } | |
| 138 | + | |
| 139 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | +<?php | |
| 2 | +require_once 'linkedin.php'; | |
| 3 | +include_once("../../ms_configura.php"); | |
| 4 | +$consumer_key = $linkedinoauth["consumerkey"]; | |
| 5 | +$consumer_secret = $linkedinoauth["consumersecret"]; | |
| 6 | +echo "<pre>"; | |
| 7 | +# First step is to initialize with your consumer key and secret. We'll use an out-of-band oauth_callback | |
| 8 | +$linkedin = new LinkedIn($consumer_key, $consumer_secret, "oob"); | |
| 9 | +$linkedin->debug = true; | |
| 10 | + | |
| 11 | +# Now we retrieve a request token. It will be set as $linkedin->request_token | |
| 12 | +$linkedin->getRequestToken(); | |
| 13 | + | |
| 14 | +# With a request token in hand, we can generate an authorization URL, which we'll direct the user to | |
| 15 | +echo "Authorization URL: " . $linkedin->generateAuthorizeUrl() . "\n\n"; | |
| 16 | + | |
| 17 | +# After logging in, the user will be presented with an OAuth Verifier, which you would then ask the member to enter in a UI you present. Once you have the OAuth verifier, set it here: | |
| 18 | + | |
| 19 | +echo "Enter OAuth Verifier:\n"; | |
| 20 | +$handle = fopen("php://stdin", "r"); | |
| 21 | +$oauth_verifier = trim(fgets($handle)); | |
| 22 | + | |
| 23 | +$linkedin->getAccessToken($oauth_verifier); | |
| 24 | + | |
| 25 | +# You now have a $linkedin->access_token and can make calls on behalf of the current member | |
| 26 | +$xml_response = $linkedin->getProfile("~:(id,first-name,last-name,headline,picture-url)"); | |
| 27 | + | |
| 28 | +echo $xml_response; | |
| 29 | + | |
| 30 | +# Let's set our status | |
| 31 | + | |
| 32 | +$xml_response2 = $linkedin->setStatus("setting my status using the LinkedIn API."); | |
| 33 | +echo $xml_response2; | |
| 34 | + | |
| 35 | +# Let's do a search! | |
| 36 | +$search_response = $linkedin->search("?company=Google&count=10"); | |
| 37 | +echo $search_response; | |
| 38 | + | |
| 39 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | +<?php | |
| 2 | +require_once 'linkedin.php'; | |
| 3 | + | |
| 4 | +# Use this to used already retrieved access token credentials for testing. | |
| 5 | + | |
| 6 | +$consumer_key = ""; | |
| 7 | +$consumer_secret = ""; | |
| 8 | +$access_token = ""; | |
| 9 | +$access_token_secret = ""; | |
| 10 | + | |
| 11 | +# First step is to initialize with your consumer key and secret. We'll use an out-of-band oauth_callback | |
| 12 | +$linkedin = new LinkedIn($consumer_key, $consumer_secret, "oob"); | |
| 13 | +$linkedin->debug = true; | |
| 14 | + | |
| 15 | +$linkedin->access_token = new OAuthConsumer($access_token, $access_token_secret, 1); | |
| 16 | + | |
| 17 | +# Let's do a search! | |
| 18 | +$search_response = $linkedin->search("?company=Google&count=10"); | |
| 19 | + | |
| 20 | +echo $search_response; | |
| 21 | + | |
| 22 | +?> | ... | ... |
pacotes/linkedinoauth/tests/Mock_OAuthBaseStringRequest.php
0 → 100644
| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * A very simple class that you can pass a base-string, and then have it returned again. | |
| 5 | + * Used for testing the signature-methods | |
| 6 | + */ | |
| 7 | +class Mock_OAuthBaseStringRequest { | |
| 8 | + private $provided_base_string; | |
| 9 | + public $base_string; // legacy | |
| 10 | + public function __construct($bs) { $this->provided_base_string = $bs; } | |
| 11 | + public function get_signature_base_string() { return $this->provided_base_string; } | |
| 12 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * A mock store for testing | |
| 5 | + */ | |
| 6 | +class Mock_OAuthDataStore extends OAuthDataStore { | |
| 7 | + private $consumer; | |
| 8 | + private $request_token; | |
| 9 | + private $access_token; | |
| 10 | + private $nonce; | |
| 11 | + | |
| 12 | + function __construct() { | |
| 13 | + $this->consumer = new OAuthConsumer("key", "secret", NULL); | |
| 14 | + $this->request_token = new OAuthToken("requestkey", "requestsecret", 1); | |
| 15 | + $this->access_token = new OAuthToken("accesskey", "accesssecret", 1); | |
| 16 | + $this->nonce = "nonce"; | |
| 17 | + } | |
| 18 | + | |
| 19 | + function lookup_consumer($consumer_key) { | |
| 20 | + if ($consumer_key == $this->consumer->key) return $this->consumer; | |
| 21 | + return NULL; | |
| 22 | + } | |
| 23 | + | |
| 24 | + function lookup_token($consumer, $token_type, $token) { | |
| 25 | + $token_attrib = $token_type . "_token"; | |
| 26 | + if ($consumer->key == $this->consumer->key | |
| 27 | + && $token == $this->$token_attrib->key) { | |
| 28 | + return $this->$token_attrib; | |
| 29 | + } | |
| 30 | + return NULL; | |
| 31 | + } | |
| 32 | + | |
| 33 | + function lookup_nonce($consumer, $token, $nonce, $timestamp) { | |
| 34 | + if ($consumer->key == $this->consumer->key | |
| 35 | + && (($token && $token->key == $this->request_token->key) | |
| 36 | + || ($token && $token->key == $this->access_token->key)) | |
| 37 | + && $nonce == $this->nonce) { | |
| 38 | + return $this->nonce; | |
| 39 | + } | |
| 40 | + return NULL; | |
| 41 | + } | |
| 42 | + | |
| 43 | + function new_request_token($consumer) { | |
| 44 | + if ($consumer->key == $this->consumer->key) { | |
| 45 | + return $this->request_token; | |
| 46 | + } | |
| 47 | + return NULL; | |
| 48 | + } | |
| 49 | + | |
| 50 | + function new_access_token($token, $consumer) { | |
| 51 | + if ($consumer->key == $this->consumer->key | |
| 52 | + && $token->key == $this->request_token->key) { | |
| 53 | + return $this->access_token; | |
| 54 | + } | |
| 55 | + return NULL; | |
| 56 | + } | |
| 57 | +} | |
| 0 | 58 | \ No newline at end of file | ... | ... |
pacotes/linkedinoauth/tests/Mock_OAuthSignatureMethod_RSA_SHA1.php
0 → 100644
| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * A mock implementation of OAuthSignatureMethod_RSA_SHA1 | |
| 5 | + * Always returns the signatures described in | |
| 6 | + * http://wiki.oauth.net/TestCases section 9.3 ("RSA-SHA1") | |
| 7 | + */ | |
| 8 | +class Mock_OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod_RSA_SHA1 { | |
| 9 | + public function fetch_private_cert(&$request) { | |
| 10 | + $cert = <<<EOD | |
| 11 | +-----BEGIN PRIVATE KEY----- | |
| 12 | +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V | |
| 13 | +A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d | |
| 14 | +7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ | |
| 15 | +hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H | |
| 16 | +X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm | |
| 17 | +uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw | |
| 18 | +rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z | |
| 19 | +zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn | |
| 20 | +qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG | |
| 21 | +WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno | |
| 22 | +cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+ | |
| 23 | +3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8 | |
| 24 | +AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54 | |
| 25 | +Lw03eHTNQghS0A== | |
| 26 | +-----END PRIVATE KEY----- | |
| 27 | +EOD; | |
| 28 | + return $cert; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public function fetch_public_cert(&$request) { | |
| 32 | + $cert = <<<EOD | |
| 33 | +-----BEGIN CERTIFICATE----- | |
| 34 | +MIIBpjCCAQ+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAZMRcwFQYDVQQDDA5UZXN0 | |
| 35 | +IFByaW5jaXBhbDAeFw03MDAxMDEwODAwMDBaFw0zODEyMzEwODAwMDBaMBkxFzAV | |
| 36 | +BgNVBAMMDlRlc3QgUHJpbmNpcGFsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB | |
| 37 | +gQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlY | |
| 38 | +zypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp/IpH7kH41Etb | |
| 39 | +mUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQABMA0GCSqGSIb3 | |
| 40 | +DQEBBQUAA4GBAGZLPEuJ5SiJ2ryq+CmEGOXfvlTtEL2nuGtr9PewxkgnOjZpUy+d | |
| 41 | +4TvuXJbNQc8f4AMWL/tO9w0Fk80rWKp9ea8/df4qMq5qlFWlx6yOLQxumNOmECKb | |
| 42 | +WpkUQDIDJEoFUzKMVuJf4KO/FJ345+BNLGgbJ6WujreoM1X/gYfdnJ/J | |
| 43 | +-----END CERTIFICATE----- | |
| 44 | +EOD; | |
| 45 | + return $cert; | |
| 46 | + } | |
| 47 | +} | |
| 0 | 48 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +require 'common.php'; | |
| 4 | + | |
| 5 | +class OAuthConsumerTest extends PHPUnit_Framework_TestCase { | |
| 6 | + public function testConvertToString() { | |
| 7 | + $consumer = new OAuthConsumer('key', 'secret'); | |
| 8 | + $this->assertEquals('OAuthConsumer[key=key,secret=secret]', (string) $consumer); | |
| 9 | + } | |
| 10 | +} | |
| 0 | 11 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,317 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/* | |
| 4 | + * Tests of OAuthRequest | |
| 5 | + * | |
| 6 | + * The tests works by using OAuthTestUtils::build_request | |
| 7 | + * to populare $_SERVER, $_GET & $_POST. | |
| 8 | + * | |
| 9 | + * Most of the base string and signature tests | |
| 10 | + * are either very simple or based upon | |
| 11 | + * http://wiki.oauth.net/TestCases | |
| 12 | + */ | |
| 13 | + | |
| 14 | +require_once dirname(__FILE__) . '/common.php'; | |
| 15 | + | |
| 16 | +class OAuthRequestTest extends PHPUnit_Framework_TestCase { | |
| 17 | + public function testCanGetSingleParameter() { | |
| 18 | + // Yes, a awesomely boring test.. But if this doesn't work, the other tests is unreliable | |
| 19 | + $request = new OAuthRequest('', '', array('test'=>'foo')); | |
| 20 | + $this->assertEquals( 'foo', $request->get_parameter('test'), 'Failed to read back parameter'); | |
| 21 | + | |
| 22 | + $request = new OAuthRequest('', '', array('test'=>array('foo', 'bar'))); | |
| 23 | + $this->assertEquals( array('foo', 'bar'), $request->get_parameter('test'), 'Failed to read back parameter'); | |
| 24 | + | |
| 25 | + | |
| 26 | + $request = new OAuthRequest('', '', array('test'=>'foo', 'bar'=>'baz')); | |
| 27 | + $this->assertEquals( 'foo', $request->get_parameter('test'), 'Failed to read back parameter'); | |
| 28 | + $this->assertEquals( 'baz', $request->get_parameter('bar'), 'Failed to read back parameter'); | |
| 29 | + } | |
| 30 | + | |
| 31 | + public function testGetAllParameters() { | |
| 32 | + // Yes, a awesomely boring test.. But if this doesn't work, the other tests is unreliable | |
| 33 | + $request = new OAuthRequest('', '', array('test'=>'foo')); | |
| 34 | + $this->assertEquals( array('test'=>'foo'), $request->get_parameters(), 'Failed to read back parameters'); | |
| 35 | + | |
| 36 | + $request = new OAuthRequest('', '', array('test'=>'foo', 'bar'=>'baz')); | |
| 37 | + $this->assertEquals( array('test'=>'foo', 'bar'=>'baz'), $request->get_parameters(), 'Failed to read back parameters'); | |
| 38 | + | |
| 39 | + $request = new OAuthRequest('', '', array('test'=>array('foo', 'bar'))); | |
| 40 | + $this->assertEquals( array('test'=>array('foo', 'bar')), $request->get_parameters(), 'Failed to read back parameters'); | |
| 41 | + } | |
| 42 | + | |
| 43 | + public function testSetParameters() { | |
| 44 | + $request = new OAuthRequest('', ''); | |
| 45 | + $this->assertEquals( NULL, $request->get_parameter('test'), 'Failed to assert that non-existing parameter is NULL'); | |
| 46 | + | |
| 47 | + $request->set_parameter('test', 'foo'); | |
| 48 | + $this->assertEquals( 'foo', $request->get_parameter('test'), 'Failed to set single-entry parameter'); | |
| 49 | + | |
| 50 | + $request->set_parameter('test', 'bar'); | |
| 51 | + $this->assertEquals( array('foo', 'bar'), $request->get_parameter('test'), 'Failed to set single-entry parameter'); | |
| 52 | + | |
| 53 | + $request->set_parameter('test', 'bar', false); | |
| 54 | + $this->assertEquals( 'bar', $request->get_parameter('test'), 'Failed to set single-entry parameter'); | |
| 55 | + } | |
| 56 | + | |
| 57 | + public function testUnsetParameter() { | |
| 58 | + $request = new OAuthRequest('', ''); | |
| 59 | + $this->assertEquals( NULL, $request->get_parameter('test')); | |
| 60 | + | |
| 61 | + $request->set_parameter('test', 'foo'); | |
| 62 | + $this->assertEquals( 'foo', $request->get_parameter('test')); | |
| 63 | + | |
| 64 | + $request->unset_parameter('test'); | |
| 65 | + $this->assertEquals( NULL, $request->get_parameter('test'), 'Failed to unset parameter'); | |
| 66 | + } | |
| 67 | + | |
| 68 | + public function testCreateRequestFromConsumerAndToken() { | |
| 69 | + $cons = new OAuthConsumer('key', 'kd94hf93k423kf44'); | |
| 70 | + $token = new OAuthToken('token', 'pfkkdhi9sl3r4s00'); | |
| 71 | + | |
| 72 | + $request = OAuthRequest::from_consumer_and_token($cons, $token, 'POST', 'http://example.com'); | |
| 73 | + $this->assertEquals('POST', $request->get_normalized_http_method()); | |
| 74 | + $this->assertEquals('http://example.com', $request->get_normalized_http_url()); | |
| 75 | + $this->assertEquals('1.0', $request->get_parameter('oauth_version')); | |
| 76 | + $this->assertEquals($cons->key, $request->get_parameter('oauth_consumer_key')); | |
| 77 | + $this->assertEquals($token->key, $request->get_parameter('oauth_token')); | |
| 78 | + $this->assertEquals(time(), $request->get_parameter('oauth_timestamp')); | |
| 79 | + $this->assertRegExp('/[0-9a-f]{32}/', $request->get_parameter('oauth_nonce')); | |
| 80 | + // We don't know what the nonce will be, except it'll be md5 and hence 32 hexa digits | |
| 81 | + | |
| 82 | + $request = OAuthRequest::from_consumer_and_token($cons, $token, 'POST', 'http://example.com', array('oauth_nonce'=>'foo')); | |
| 83 | + $this->assertEquals('foo', $request->get_parameter('oauth_nonce')); | |
| 84 | + | |
| 85 | + $request = OAuthRequest::from_consumer_and_token($cons, NULL, 'POST', 'http://example.com', array('oauth_nonce'=>'foo')); | |
| 86 | + $this->assertNull($request->get_parameter('oauth_token')); | |
| 87 | + | |
| 88 | + // Test that parameters given in the $http_url instead of in the $parameters-parameter | |
| 89 | + // will still be picked up | |
| 90 | + $request = OAuthRequest::from_consumer_and_token($cons, $token, 'POST', 'http://example.com/?foo=bar'); | |
| 91 | + $this->assertEquals('http://example.com/', $request->get_normalized_http_url()); | |
| 92 | + $this->assertEquals('bar', $request->get_parameter('foo')); | |
| 93 | + } | |
| 94 | + | |
| 95 | + public function testBuildRequestFromPost() { | |
| 96 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'foo=bar&baz=blargh'); | |
| 97 | + $this->assertEquals(array('foo'=>'bar','baz'=>'blargh'), OAuthRequest::from_request()->get_parameters(), 'Failed to parse POST parameters'); | |
| 98 | + } | |
| 99 | + | |
| 100 | + public function testBuildRequestFromGet() { | |
| 101 | + OAuthTestUtils::build_request('GET', 'http://testbed/test?foo=bar&baz=blargh'); | |
| 102 | + $this->assertEquals(array('foo'=>'bar','baz'=>'blargh'), OAuthRequest::from_request()->get_parameters(), 'Failed to parse GET parameters'); | |
| 103 | + } | |
| 104 | + | |
| 105 | + public function testBuildRequestFromHeader() { | |
| 106 | + $test_header = 'OAuth realm="",oauth_foo=bar,oauth_baz="bla,rgh"'; | |
| 107 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', '', $test_header); | |
| 108 | + $this->assertEquals(array('oauth_foo'=>'bar','oauth_baz'=>'bla,rgh'), OAuthRequest::from_request()->get_parameters(), 'Failed to split auth-header correctly'); | |
| 109 | + } | |
| 110 | + | |
| 111 | + public function testHasProperParameterPriority() { | |
| 112 | + $test_header = 'OAuth realm="",oauth_foo=header'; | |
| 113 | + OAuthTestUtils::build_request('POST', 'http://testbed/test?oauth_foo=get', 'oauth_foo=post', $test_header); | |
| 114 | + $this->assertEquals('header', OAuthRequest::from_request()->get_parameter('oauth_foo'), 'Loaded parameters in with the wrong priorities'); | |
| 115 | + | |
| 116 | + OAuthTestUtils::build_request('POST', 'http://testbed/test?oauth_foo=get', 'oauth_foo=post'); | |
| 117 | + $this->assertEquals('post', OAuthRequest::from_request()->get_parameter('oauth_foo'), 'Loaded parameters in with the wrong priorities'); | |
| 118 | + | |
| 119 | + OAuthTestUtils::build_request('POST', 'http://testbed/test?oauth_foo=get'); | |
| 120 | + $this->assertEquals('get', OAuthRequest::from_request()->get_parameter('oauth_foo'), 'Loaded parameters in with the wrong priorities'); | |
| 121 | + } | |
| 122 | + | |
| 123 | + public function testNormalizeHttpMethod() { | |
| 124 | + OAuthTestUtils::build_request('POST', 'http://testbed/test'); | |
| 125 | + $this->assertEquals('POST', OAuthRequest::from_request()->get_normalized_http_method(), 'Failed to normalize HTTP method: POST'); | |
| 126 | + | |
| 127 | + OAuthTestUtils::build_request('post', 'http://testbed/test'); | |
| 128 | + $this->assertEquals('POST', OAuthRequest::from_request()->get_normalized_http_method(), 'Failed to normalize HTTP method: post'); | |
| 129 | + | |
| 130 | + OAuthTestUtils::build_request('GET', 'http://testbed/test'); | |
| 131 | + $this->assertEquals('GET', OAuthRequest::from_request()->get_normalized_http_method(), 'Failed to normalize HTTP method: GET'); | |
| 132 | + | |
| 133 | + OAuthTestUtils::build_request('PUT', 'http://testbed/test'); | |
| 134 | + $this->assertEquals('PUT', OAuthRequest::from_request()->get_normalized_http_method(), 'Failed to normalize HTTP method: PUT'); | |
| 135 | + } | |
| 136 | + | |
| 137 | + public function testNormalizeParameters() { | |
| 138 | + // This is mostly repeats of OAuthUtilTest::testParseParameters & OAuthUtilTest::TestBuildHttpQuery | |
| 139 | + | |
| 140 | + // Tests taken from | |
| 141 | + // http://wiki.oauth.net/TestCases ("Normalize Request Parameters") | |
| 142 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'name'); | |
| 143 | + $this->assertEquals( 'name=', OAuthRequest::from_request()->get_signable_parameters()); | |
| 144 | + | |
| 145 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'a=b'); | |
| 146 | + $this->assertEquals( 'a=b', OAuthRequest::from_request()->get_signable_parameters()); | |
| 147 | + | |
| 148 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'a=b&c=d'); | |
| 149 | + $this->assertEquals( 'a=b&c=d', OAuthRequest::from_request()->get_signable_parameters()); | |
| 150 | + | |
| 151 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'a=x%21y&a=x+y'); | |
| 152 | + $this->assertEquals( 'a=x%20y&a=x%21y', OAuthRequest::from_request()->get_signable_parameters()); | |
| 153 | + | |
| 154 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'x%21y=a&x=a'); | |
| 155 | + $this->assertEquals( 'x=a&x%21y=a', OAuthRequest::from_request()->get_signable_parameters()); | |
| 156 | + | |
| 157 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'a=1&c=hi there&f=25&f=50&f=a&z=p&z=t'); | |
| 158 | + $this->assertEquals( 'a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t', OAuthRequest::from_request()->get_signable_parameters()); | |
| 159 | + } | |
| 160 | + | |
| 161 | + public function testNormalizeHttpUrl() { | |
| 162 | + OAuthTestUtils::build_request('POST', 'http://example.com'); | |
| 163 | + $this->assertEquals('http://example.com', OAuthRequest::from_request()->get_normalized_http_url()); | |
| 164 | + | |
| 165 | + OAuthTestUtils::build_request('POST', 'https://example.com'); | |
| 166 | + $this->assertEquals('https://example.com', OAuthRequest::from_request()->get_normalized_http_url()); | |
| 167 | + | |
| 168 | + // Tests that http on !80 and https on !443 keeps the port | |
| 169 | + OAuthTestUtils::build_request('POST', 'http://example.com:8080'); | |
| 170 | + $this->assertEquals('http://example.com:8080', OAuthRequest::from_request()->get_normalized_http_url()); | |
| 171 | + | |
| 172 | + OAuthTestUtils::build_request('POST', 'https://example.com:80'); | |
| 173 | + $this->assertEquals('https://example.com:80', OAuthRequest::from_request()->get_normalized_http_url()); | |
| 174 | + | |
| 175 | + OAuthTestUtils::build_request('POST', 'http://example.com:443'); | |
| 176 | + $this->assertEquals('http://example.com:443', OAuthRequest::from_request()->get_normalized_http_url()); | |
| 177 | + } | |
| 178 | + | |
| 179 | + public function testBuildPostData() { | |
| 180 | + OAuthTestUtils::build_request('POST', 'http://example.com'); | |
| 181 | + $this->assertEquals('', OAuthRequest::from_request()->to_postdata()); | |
| 182 | + | |
| 183 | + OAuthTestUtils::build_request('POST', 'http://example.com', 'foo=bar'); | |
| 184 | + $this->assertEquals('foo=bar', OAuthRequest::from_request()->to_postdata()); | |
| 185 | + | |
| 186 | + OAuthTestUtils::build_request('GET', 'http://example.com?foo=bar'); | |
| 187 | + $this->assertEquals('foo=bar', OAuthRequest::from_request()->to_postdata()); | |
| 188 | + } | |
| 189 | + | |
| 190 | + public function testBuildUrl() { | |
| 191 | + OAuthTestUtils::build_request('POST', 'http://example.com'); | |
| 192 | + $this->assertEquals('http://example.com', OAuthRequest::from_request()->to_url()); | |
| 193 | + | |
| 194 | + OAuthTestUtils::build_request('POST', 'http://example.com', 'foo=bar'); | |
| 195 | + $this->assertEquals('http://example.com?foo=bar', OAuthRequest::from_request()->to_url()); | |
| 196 | + | |
| 197 | + OAuthTestUtils::build_request('GET', 'http://example.com?foo=bar'); | |
| 198 | + $this->assertEquals('http://example.com?foo=bar', OAuthRequest::from_request()->to_url()); | |
| 199 | + } | |
| 200 | + | |
| 201 | + public function testConvertToString() { | |
| 202 | + OAuthTestUtils::build_request('POST', 'http://example.com'); | |
| 203 | + $this->assertEquals('http://example.com', (string) OAuthRequest::from_request()); | |
| 204 | + | |
| 205 | + OAuthTestUtils::build_request('POST', 'http://example.com', 'foo=bar'); | |
| 206 | + $this->assertEquals('http://example.com?foo=bar', (string) OAuthRequest::from_request()); | |
| 207 | + | |
| 208 | + OAuthTestUtils::build_request('GET', 'http://example.com?foo=bar'); | |
| 209 | + $this->assertEquals('http://example.com?foo=bar', (string) OAuthRequest::from_request()); | |
| 210 | + } | |
| 211 | + | |
| 212 | + public function testBuildHeader() { | |
| 213 | + OAuthTestUtils::build_request('POST', 'http://example.com'); | |
| 214 | + $this->assertEquals('Authorization: OAuth', OAuthRequest::from_request()->to_header()); | |
| 215 | + $this->assertEquals('Authorization: OAuth realm="test"', OAuthRequest::from_request()->to_header('test')); | |
| 216 | + | |
| 217 | + OAuthTestUtils::build_request('POST', 'http://example.com', 'foo=bar'); | |
| 218 | + $this->assertEquals('Authorization: OAuth', OAuthRequest::from_request()->to_header()); | |
| 219 | + $this->assertEquals('Authorization: OAuth realm="test"', OAuthRequest::from_request()->to_header('test')); | |
| 220 | + | |
| 221 | + // Is headers supposted to be Urlencoded. More to the point: | |
| 222 | + // Should it be baz = bla,rgh or baz = bla%2Crgh ?? | |
| 223 | + // - morten.fangel | |
| 224 | + OAuthTestUtils::build_request('POST', 'http://example.com', '', 'OAuth realm="",oauth_foo=bar,oauth_baz="bla,rgh"'); | |
| 225 | + $this->assertEquals('Authorization: OAuth,oauth_foo="bar",oauth_baz="bla%2Crgh"', OAuthRequest::from_request()->to_header()); | |
| 226 | + $this->assertEquals('Authorization: OAuth realm="test",oauth_foo="bar",oauth_baz="bla%2Crgh"', OAuthRequest::from_request()->to_header('test')); | |
| 227 | + } | |
| 228 | + | |
| 229 | + public function testWontBuildHeaderWithArrayInput() { | |
| 230 | + $this->setExpectedException('OAuthException'); | |
| 231 | + OAuthTestUtils::build_request('POST', 'http://example.com', 'oauth_foo=bar&oauth_foo=baz'); | |
| 232 | + OAuthRequest::from_request()->to_header(); | |
| 233 | + } | |
| 234 | + | |
| 235 | + public function testBuildBaseString() { | |
| 236 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'n=v'); | |
| 237 | + $this->assertEquals('POST&http%3A%2F%2Ftestbed%2Ftest&n%3Dv', OAuthRequest::from_request()->get_signature_base_string()); | |
| 238 | + | |
| 239 | + OAuthTestUtils::build_request('POST', 'http://testbed/test', 'n=v&n=v2'); | |
| 240 | + $this->assertEquals('POST&http%3A%2F%2Ftestbed%2Ftest&n%3Dv%26n%3Dv2', OAuthRequest::from_request()->get_signature_base_string()); | |
| 241 | + | |
| 242 | + OAuthTestUtils::build_request('GET', 'http://example.com?n=v'); | |
| 243 | + $this->assertEquals('GET&http%3A%2F%2Fexample.com&n%3Dv', OAuthRequest::from_request()->get_signature_base_string()); | |
| 244 | + | |
| 245 | + $params = 'oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_timestamp=1191242090'; | |
| 246 | + $params .= '&oauth_nonce=hsu94j3884jdopsl&oauth_signature_method=PLAINTEXT&oauth_signature=ignored'; | |
| 247 | + OAuthTestUtils::build_request('POST', 'https://photos.example.net/request_token', $params); | |
| 248 | + $this->assertEquals('POST&https%3A%2F%2Fphotos.example.net%2Frequest_token&oauth_' | |
| 249 | + .'consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dhsu94j3884j' | |
| 250 | + .'dopsl%26oauth_signature_method%3DPLAINTEXT%26oauth_timestam' | |
| 251 | + .'p%3D1191242090%26oauth_version%3D1.0', | |
| 252 | + OAuthRequest::from_request()->get_signature_base_string()); | |
| 253 | + | |
| 254 | + $params = 'file=vacation.jpg&size=original&oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03'; | |
| 255 | + $params .= '&oauth_token=nnch734d00sl2jdk&oauth_timestamp=1191242096&oauth_nonce=kllo9940pd9333jh'; | |
| 256 | + $params .= '&oauth_signature=ignored&oauth_signature_method=HMAC-SHA1'; | |
| 257 | + OAuthTestUtils::build_request('GET', 'http://photos.example.net/photos?'.$params); | |
| 258 | + $this->assertEquals('GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation' | |
| 259 | + .'.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%' | |
| 260 | + .'3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26o' | |
| 261 | + .'auth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jd' | |
| 262 | + .'k%26oauth_version%3D1.0%26size%3Doriginal', | |
| 263 | + OAuthRequest::from_request()->get_signature_base_string()); | |
| 264 | + } | |
| 265 | + | |
| 266 | + public function testBuildSignature() { | |
| 267 | + $params = 'file=vacation.jpg&size=original&oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03'; | |
| 268 | + $params .= '&oauth_token=nnch734d00sl2jdk&oauth_timestamp=1191242096&oauth_nonce=kllo9940pd9333jh'; | |
| 269 | + $params .= '&oauth_signature=ignored&oauth_signature_method=HMAC-SHA1'; | |
| 270 | + OAuthTestUtils::build_request('GET', 'http://photos.example.net/photos?'.$params); | |
| 271 | + $r = OAuthRequest::from_request(); | |
| 272 | + | |
| 273 | + $cons = new OAuthConsumer('key', 'kd94hf93k423kf44'); | |
| 274 | + $token = new OAuthToken('token', 'pfkkdhi9sl3r4s00'); | |
| 275 | + | |
| 276 | + $hmac = new OAuthSignatureMethod_HMAC_SHA1(); | |
| 277 | + $plaintext = new OAuthSignatureMethod_PLAINTEXT(); | |
| 278 | + | |
| 279 | + $this->assertEquals('tR3+Ty81lMeYAr/Fid0kMTYa/WM=', $r->build_signature($hmac, $cons, $token)); | |
| 280 | + $this->assertEquals('kd94hf93k423kf44&pfkkdhi9sl3r4s00', $r->build_signature($plaintext, $cons, $token)); | |
| 281 | + } | |
| 282 | + | |
| 283 | + public function testSign() { | |
| 284 | + $params = 'file=vacation.jpg&size=original&oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03'; | |
| 285 | + $params .= '&oauth_token=nnch734d00sl2jdk&oauth_timestamp=1191242096&oauth_nonce=kllo9940pd9333jh'; | |
| 286 | + $params .= '&oauth_signature=__ignored__&oauth_signature_method=HMAC-SHA1'; | |
| 287 | + OAuthTestUtils::build_request('GET', 'http://photos.example.net/photos?'.$params); | |
| 288 | + $r = OAuthRequest::from_request(); | |
| 289 | + | |
| 290 | + $cons = new OAuthConsumer('key', 'kd94hf93k423kf44'); | |
| 291 | + $token = new OAuthToken('token', 'pfkkdhi9sl3r4s00'); | |
| 292 | + | |
| 293 | + $hmac = new OAuthSignatureMethod_HMAC_SHA1(); | |
| 294 | + $plaintext = new OAuthSignatureMethod_PLAINTEXT(); | |
| 295 | + | |
| 296 | + // We need to test both what the parameter is, and how the serialized request is.. | |
| 297 | + | |
| 298 | + $r->sign_request($hmac, $cons, $token); | |
| 299 | + $this->assertEquals('HMAC-SHA1', $r->get_parameter('oauth_signature_method')); | |
| 300 | + $this->assertEquals('tR3+Ty81lMeYAr/Fid0kMTYa/WM=', $r->get_parameter('oauth_signature')); | |
| 301 | + $expectedPostdata = 'file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&' | |
| 302 | + . 'oauth_signature=tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D&oauth_signature_method=HMAC-SHA1&' | |
| 303 | + . 'oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original'; | |
| 304 | + $this->assertEquals( $expectedPostdata, $r->to_postdata()); | |
| 305 | + | |
| 306 | + $r->sign_request($plaintext, $cons, $token); | |
| 307 | + $this->assertEquals('PLAINTEXT', $r->get_parameter('oauth_signature_method')); | |
| 308 | + $this->assertEquals('kd94hf93k423kf44&pfkkdhi9sl3r4s00', $r->get_parameter('oauth_signature')); | |
| 309 | + $expectedPostdata = 'file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&' | |
| 310 | + . 'oauth_signature=kd94hf93k423kf44%26pfkkdhi9sl3r4s00&oauth_signature_method=PLAINTEXT&' | |
| 311 | + . 'oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original'; | |
| 312 | + $this->assertEquals( $expectedPostdata, $r->to_postdata()); | |
| 313 | + | |
| 314 | + } | |
| 315 | +} | |
| 316 | + | |
| 317 | +?> | |
| 0 | 318 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,225 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +require_once dirname(__FILE__) . '/common.php'; | |
| 4 | +require_once dirname(__FILE__) . '/Mock_OAuthDataStore.php'; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * Tests of OAuthUtil | |
| 8 | + */ | |
| 9 | +class OAuthServerTest extends PHPUnit_Framework_TestCase { | |
| 10 | + private $consumer; | |
| 11 | + private $request_token; | |
| 12 | + private $access_token; | |
| 13 | + private $hmac_sha1; | |
| 14 | + private $plaintext; | |
| 15 | + private $server; | |
| 16 | + | |
| 17 | + public function setUp() { | |
| 18 | + $this->consumer = new OAuthConsumer('key', 'secret'); | |
| 19 | + $this->request_token = new OAuthToken('requestkey', 'requestsecret'); | |
| 20 | + $this->access_token = new OAuthToken('accesskey', 'accesssecret'); | |
| 21 | + | |
| 22 | + $this->hmac_sha1 = new OAuthSignatureMethod_HMAC_SHA1(); | |
| 23 | + $this->plaintext = new OAuthSignatureMethod_PLAINTEXT(); | |
| 24 | + | |
| 25 | + $this->server = new OAuthServer( new Mock_OAuthDataStore() ); | |
| 26 | + $this->server->add_signature_method( $this->hmac_sha1 ); | |
| 27 | + $this->server->add_signature_method( $this->plaintext ); | |
| 28 | + } | |
| 29 | + | |
| 30 | + public function testAcceptValidRequest() { | |
| 31 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 32 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 33 | + list($consumer, $token) = $this->server->verify_request( $request ); | |
| 34 | + $this->assertEquals( $this->consumer, $consumer ); | |
| 35 | + $this->assertEquals( $this->access_token, $token ); | |
| 36 | + | |
| 37 | + $request->sign_request( $this->hmac_sha1, $this->consumer, $this->access_token ); | |
| 38 | + list($consumer, $token) = $this->server->verify_request( $request ); | |
| 39 | + $this->assertEquals( $this->consumer, $consumer ); | |
| 40 | + $this->assertEquals( $this->access_token, $token ); | |
| 41 | + } | |
| 42 | + | |
| 43 | + public function testAcceptRequestWithoutVersion() { | |
| 44 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 45 | + $request->unset_parameter('oauth_version'); | |
| 46 | + $request->sign_request( $this->hmac_sha1, $this->consumer, $this->access_token ); | |
| 47 | + | |
| 48 | + $this->server->verify_request( $request ); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public function testRejectRequestSignedWithRequestToken() { | |
| 52 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->request_token, 'POST', 'http://example.com'); | |
| 53 | + $request->sign_request( $this->plaintext, $this->consumer, $this->request_token ); | |
| 54 | + | |
| 55 | + $this->setExpectedException('OAuthException'); | |
| 56 | + $this->server->verify_request( $request ); | |
| 57 | + } | |
| 58 | + | |
| 59 | + public function testRejectRequestWithMissingParameters() { | |
| 60 | + // The list of required parameters is taken from | |
| 61 | + // Chapter 7 ("Accessing Protected Resources") | |
| 62 | + | |
| 63 | + $required_parameters = array( | |
| 64 | + 'oauth_consumer_key', | |
| 65 | + 'oauth_token', | |
| 66 | + 'oauth_signature_method', | |
| 67 | + 'oauth_signature', | |
| 68 | + 'oauth_timestamp', | |
| 69 | + 'oauth_nonce' | |
| 70 | + ); | |
| 71 | + | |
| 72 | + foreach( $required_parameters AS $required ) { | |
| 73 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 74 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 75 | + try { | |
| 76 | + $request->unset_parameter( $required ); | |
| 77 | + $this->server->verify_request($request); | |
| 78 | + $this->fail('Allowed a request without `' . $required . '`'); | |
| 79 | + } catch( OAuthException $e ) { /* expected */ } | |
| 80 | + } | |
| 81 | + } | |
| 82 | + | |
| 83 | + public function testRejectPastTimestamp() { | |
| 84 | + // We change the timestamp to be 10 hours ago, it should throw an exception | |
| 85 | + | |
| 86 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 87 | + $request->set_parameter( 'oauth_timestamp', $request->get_parameter('oauth_timestamp') - 10*60*60, false); | |
| 88 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 89 | + | |
| 90 | + $this->setExpectedException('OAuthException'); | |
| 91 | + $this->server->verify_request($request); | |
| 92 | + } | |
| 93 | + | |
| 94 | + public function testRejectFutureTimestamp() { | |
| 95 | + // We change the timestamp to be 10 hours in the future, it should throw an exception | |
| 96 | + | |
| 97 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 98 | + $request->set_parameter( 'oauth_timestamp', $request->get_parameter('oauth_timestamp') + 10*60*60, false); | |
| 99 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 100 | + | |
| 101 | + $this->setExpectedException('OAuthException'); | |
| 102 | + $this->server->verify_request($request); | |
| 103 | + } | |
| 104 | + | |
| 105 | + public function testRejectUsedNonce() { | |
| 106 | + // We give a known nonce and should see an exception | |
| 107 | + | |
| 108 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 109 | + // The Mock datastore is set to say that the `nonce` nonce is known | |
| 110 | + $request->set_parameter( 'oauth_nonce', 'nonce', false); | |
| 111 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 112 | + | |
| 113 | + $this->setExpectedException('OAuthException'); | |
| 114 | + $this->server->verify_request($request); | |
| 115 | + } | |
| 116 | + | |
| 117 | + public function testRejectInvalidSignature() { | |
| 118 | + // We change the signature post-signing to be something invalid | |
| 119 | + | |
| 120 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 121 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 122 | + $request->set_parameter( 'oauth_signature', '__whatever__', false); | |
| 123 | + | |
| 124 | + $this->setExpectedException('OAuthException'); | |
| 125 | + $this->server->verify_request($request); | |
| 126 | + } | |
| 127 | + | |
| 128 | + public function testRejectInvalidConsumer() { | |
| 129 | + // We use the consumer-key "unknown", which isn't known by the datastore. | |
| 130 | + | |
| 131 | + $unknown_consumer = new OAuthConsumer('unknown', '__unused__'); | |
| 132 | + | |
| 133 | + $request = OAuthRequest::from_consumer_and_token( $unknown_consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 134 | + $request->sign_request( $this->plaintext, $unknown_consumer, $this->access_token ); | |
| 135 | + | |
| 136 | + $this->setExpectedException('OAuthException'); | |
| 137 | + $this->server->verify_request( $request ); | |
| 138 | + } | |
| 139 | + | |
| 140 | + public function testRejectInvalidToken() { | |
| 141 | + // We use the access-token "unknown" which isn't known by the datastore | |
| 142 | + | |
| 143 | + $unknown_token = new OAuthToken('unknown', '__unused__'); | |
| 144 | + | |
| 145 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $unknown_token, 'POST', 'http://example.com'); | |
| 146 | + $request->sign_request( $this->plaintext, $this->consumer, $unknown_token ); | |
| 147 | + | |
| 148 | + $this->setExpectedException('OAuthException'); | |
| 149 | + $this->server->verify_request( $request ); | |
| 150 | + } | |
| 151 | + | |
| 152 | + public function testRejectUnknownSignatureMethod() { | |
| 153 | + // We use a server that only supports HMAC-SHA1, but requests with PLAINTEXT signature | |
| 154 | + | |
| 155 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 156 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 157 | + | |
| 158 | + $server = new OAuthServer( new Mock_OAuthDataStore() ); | |
| 159 | + $server->add_signature_method( $this->hmac_sha1 ); | |
| 160 | + | |
| 161 | + $this->setExpectedException('OAuthException'); | |
| 162 | + $server->verify_request( $request ); | |
| 163 | + } | |
| 164 | + | |
| 165 | + public function testRejectUnknownVersion() { | |
| 166 | + // We use the version "1.0a" which isn't "1.0", so reject the request | |
| 167 | + | |
| 168 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 169 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 170 | + $request->set_parameter('oauth_version', '1.0a', false); | |
| 171 | + | |
| 172 | + $this->setExpectedException('OAuthException'); | |
| 173 | + $this->server->verify_request( $request ); | |
| 174 | + } | |
| 175 | + | |
| 176 | + public function testCreateRequestToken() { | |
| 177 | + // We request a new Request Token | |
| 178 | + | |
| 179 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, NULL, 'POST', 'http://example.com'); | |
| 180 | + $request->sign_request( $this->plaintext, $this->consumer, NULL ); | |
| 181 | + | |
| 182 | + $token = $this->server->fetch_request_token($request); | |
| 183 | + $this->assertEquals($this->request_token, $token); | |
| 184 | + } | |
| 185 | + | |
| 186 | + public function testRejectSignedRequestTokenRequest() { | |
| 187 | + // We request a new Request Token, but the request is signed with a token which should fail | |
| 188 | + | |
| 189 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->request_token, 'POST', 'http://example.com'); | |
| 190 | + $request->sign_request( $this->plaintext, $this->consumer, $this->request_token ); | |
| 191 | + | |
| 192 | + $this->setExpectedException('OAuthException'); | |
| 193 | + $token = $this->server->fetch_request_token($request); | |
| 194 | + } | |
| 195 | + | |
| 196 | + public function testCreateAccessToken() { | |
| 197 | + // We request a new Access Token | |
| 198 | + | |
| 199 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->request_token, 'POST', 'http://example.com'); | |
| 200 | + $request->sign_request( $this->plaintext, $this->consumer, $this->request_token ); | |
| 201 | + | |
| 202 | + $token = $this->server->fetch_access_token($request); | |
| 203 | + $this->assertEquals($this->access_token, $token); | |
| 204 | + } | |
| 205 | + | |
| 206 | + public function testRejectUnsignedAccessTokenRequest() { | |
| 207 | + // We request a new Access Token, but we didn't sign the request with a Access Token | |
| 208 | + | |
| 209 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, NULL, 'POST', 'http://example.com'); | |
| 210 | + $request->sign_request( $this->plaintext, $this->consumer, NULL ); | |
| 211 | + | |
| 212 | + $this->setExpectedException('OAuthException'); | |
| 213 | + $token = $this->server->fetch_access_token($request); | |
| 214 | + } | |
| 215 | + | |
| 216 | + public function testRejectAccessTokenSignedAccessTokenRequest() { | |
| 217 | + // We request a new Access Token, but the request is signed with an access token, so fail! | |
| 218 | + | |
| 219 | + $request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com'); | |
| 220 | + $request->sign_request( $this->plaintext, $this->consumer, $this->access_token ); | |
| 221 | + | |
| 222 | + $this->setExpectedException('OAuthException'); | |
| 223 | + $token = $this->server->fetch_access_token($request); | |
| 224 | + } | |
| 225 | +} | ... | ... |
pacotes/linkedinoauth/tests/OAuthSignatureMethodHmacSha1Test.php
0 → 100644
| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +require_once 'common.php'; | |
| 4 | +require_once 'Mock_OAuthBaseStringRequest.php'; | |
| 5 | + | |
| 6 | +class OAuthSignatureMethodHmacSha1Test extends PHPUnit_Framework_TestCase { | |
| 7 | + private $method; | |
| 8 | + | |
| 9 | + public function setUp() { | |
| 10 | + $this->method = new OAuthSignatureMethod_HMAC_SHA1(); | |
| 11 | + } | |
| 12 | + | |
| 13 | + public function testIdentifyAsHmacSha1() { | |
| 14 | + $this->assertEquals('HMAC-SHA1', $this->method->get_name()); | |
| 15 | + } | |
| 16 | + | |
| 17 | + public function testBuildSignature() { | |
| 18 | + // Tests taken from http://wiki.oauth.net/TestCases section 9.2 ("HMAC-SHA1") | |
| 19 | + $request = new Mock_OAuthBaseStringRequest('bs'); | |
| 20 | + $consumer = new OAuthConsumer('__unused__', 'cs'); | |
| 21 | + $token = NULL; | |
| 22 | + $this->assertEquals('egQqG5AJep5sJ7anhXju1unge2I=', $this->method->build_signature( $request, $consumer, $token) ); | |
| 23 | + | |
| 24 | + $request = new Mock_OAuthBaseStringRequest('bs'); | |
| 25 | + $consumer = new OAuthConsumer('__unused__', 'cs'); | |
| 26 | + $token = new OAuthToken('__unused__', 'ts'); | |
| 27 | + $this->assertEquals('VZVjXceV7JgPq/dOTnNmEfO0Fv8=', $this->method->build_signature( $request, $consumer, $token) ); | |
| 28 | + | |
| 29 | + $request = new Mock_OAuthBaseStringRequest('GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26' | |
| 30 | + . 'oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26' | |
| 31 | + . 'oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal'); | |
| 32 | + $consumer = new OAuthConsumer('__unused__', 'kd94hf93k423kf44'); | |
| 33 | + $token = new OAuthToken('__unused__', 'pfkkdhi9sl3r4s00'); | |
| 34 | + $this->assertEquals('tR3+Ty81lMeYAr/Fid0kMTYa/WM=', $this->method->build_signature( $request, $consumer, $token) ); | |
| 35 | + } | |
| 36 | + | |
| 37 | + public function testVerifySignature() { | |
| 38 | + // Tests taken from http://wiki.oauth.net/TestCases section 9.2 ("HMAC-SHA1") | |
| 39 | + $request = new Mock_OAuthBaseStringRequest('bs'); | |
| 40 | + $consumer = new OAuthConsumer('__unused__', 'cs'); | |
| 41 | + $token = NULL; | |
| 42 | + $signature = 'egQqG5AJep5sJ7anhXju1unge2I='; | |
| 43 | + $this->assertTrue( $this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 44 | + | |
| 45 | + $request = new Mock_OAuthBaseStringRequest('bs'); | |
| 46 | + $consumer = new OAuthConsumer('__unused__', 'cs'); | |
| 47 | + $token = new OAuthToken('__unused__', 'ts'); | |
| 48 | + $signature = 'VZVjXceV7JgPq/dOTnNmEfO0Fv8='; | |
| 49 | + $this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 50 | + | |
| 51 | + $request = new Mock_OAuthBaseStringRequest('GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26' | |
| 52 | + . 'oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26' | |
| 53 | + . 'oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal'); | |
| 54 | + $consumer = new OAuthConsumer('__unused__', 'kd94hf93k423kf44'); | |
| 55 | + $token = new OAuthToken('__unused__', 'pfkkdhi9sl3r4s00'); | |
| 56 | + $signature = 'tR3+Ty81lMeYAr/Fid0kMTYa/WM='; | |
| 57 | + $this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 58 | + | |
| 59 | + } | |
| 60 | +} | |
| 0 | 61 | \ No newline at end of file | ... | ... |
pacotes/linkedinoauth/tests/OAuthSignatureMethodPlaintextTest.php
0 → 100644
| ... | ... | @@ -0,0 +1,79 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +require_once 'common.php'; | |
| 4 | +require_once 'Mock_OAuthBaseStringRequest.php'; | |
| 5 | + | |
| 6 | +class OAuthSignatureMethodPlaintextTest extends PHPUnit_Framework_TestCase { | |
| 7 | + private $method; | |
| 8 | + | |
| 9 | + public function setUp() { | |
| 10 | + $this->method = new OAuthSignatureMethod_PLAINTEXT(); | |
| 11 | + } | |
| 12 | + | |
| 13 | + public function testIdentifyAsPlaintext() { | |
| 14 | + $this->assertEquals('PLAINTEXT', $this->method->get_name()); | |
| 15 | + } | |
| 16 | + | |
| 17 | + public function testBuildSignature() { | |
| 18 | + // Tests based on from http://wiki.oauth.net/TestCases section 9.2 ("HMAC-SHA1") | |
| 19 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 20 | + $consumer = new OAuthConsumer('__unused__', 'cs'); | |
| 21 | + $token = NULL; | |
| 22 | + $this->assertEquals('cs&', $this->method->build_signature( $request, $consumer, $token) ); | |
| 23 | + | |
| 24 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 25 | + $consumer = new OAuthConsumer('__unused__', 'cs'); | |
| 26 | + $token = new OAuthToken('__unused__', 'ts'); | |
| 27 | + $this->assertEquals('cs&ts', $this->method->build_signature( $request, $consumer, $token) ); | |
| 28 | + | |
| 29 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 30 | + $consumer = new OAuthConsumer('__unused__', 'kd94hf93k423kf44'); | |
| 31 | + $token = new OAuthToken('__unused__', 'pfkkdhi9sl3r4s00'); | |
| 32 | + $this->assertEquals('kd94hf93k423kf44&pfkkdhi9sl3r4s00', $this->method->build_signature( $request, $consumer, $token) ); | |
| 33 | + | |
| 34 | + // Tests taken from Chapter 9.4.1 ("Generating Signature") from the spec | |
| 35 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 36 | + $consumer = new OAuthConsumer('__unused__', 'djr9rjt0jd78jf88'); | |
| 37 | + $token = new OAuthToken('__unused__', 'jjd999tj88uiths3'); | |
| 38 | + $this->assertEquals('djr9rjt0jd78jf88&jjd999tj88uiths3', $this->method->build_signature( $request, $consumer, $token) ); | |
| 39 | + | |
| 40 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 41 | + $consumer = new OAuthConsumer('__unused__', 'djr9rjt0jd78jf88'); | |
| 42 | + $token = new OAuthToken('__unused__', 'jjd99$tj88uiths3'); | |
| 43 | + $this->assertEquals('djr9rjt0jd78jf88&jjd99%24tj88uiths3', $this->method->build_signature( $request, $consumer, $token) ); | |
| 44 | + } | |
| 45 | + | |
| 46 | + public function testVerifySignature() { | |
| 47 | + // Tests based on from http://wiki.oauth.net/TestCases section 9.2 ("HMAC-SHA1") | |
| 48 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 49 | + $consumer = new OAuthConsumer('__unused__', 'cs'); | |
| 50 | + $token = NULL; | |
| 51 | + $signature = 'cs&'; | |
| 52 | + $this->assertTrue( $this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 53 | + | |
| 54 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 55 | + $consumer = new OAuthConsumer('__unused__', 'cs'); | |
| 56 | + $token = new OAuthToken('__unused__', 'ts'); | |
| 57 | + $signature = 'cs&ts'; | |
| 58 | + $this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 59 | + | |
| 60 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 61 | + $consumer = new OAuthConsumer('__unused__', 'kd94hf93k423kf44'); | |
| 62 | + $token = new OAuthToken('__unused__', 'pfkkdhi9sl3r4s00'); | |
| 63 | + $signature = 'kd94hf93k423kf44&pfkkdhi9sl3r4s00'; | |
| 64 | + $this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 65 | + | |
| 66 | + // Tests taken from Chapter 9.4.1 ("Generating Signature") from the spec | |
| 67 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 68 | + $consumer = new OAuthConsumer('__unused__', 'djr9rjt0jd78jf88'); | |
| 69 | + $token = new OAuthToken('__unused__', 'jjd999tj88uiths3'); | |
| 70 | + $signature = 'djr9rjt0jd78jf88&jjd999tj88uiths3'; | |
| 71 | + $this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 72 | + | |
| 73 | + $request = new Mock_OAuthBaseStringRequest('__unused__'); | |
| 74 | + $consumer = new OAuthConsumer('__unused__', 'djr9rjt0jd78jf88'); | |
| 75 | + $token = new OAuthToken('__unused__', 'jjd99$tj88uiths3'); | |
| 76 | + $signature = 'djr9rjt0jd78jf88&jjd99%24tj88uiths3'; | |
| 77 | + $this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 78 | + } | |
| 79 | +} | |
| 0 | 80 | \ No newline at end of file | ... | ... |
pacotes/linkedinoauth/tests/OAuthSignatureMethodRsaSha1Test.php
0 → 100644
| ... | ... | @@ -0,0 +1,43 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +require_once 'common.php'; | |
| 4 | +require_once 'Mock_OAuthBaseStringRequest.php'; | |
| 5 | +require_once 'Mock_OAuthSignatureMethod_RSA_SHA1.php'; | |
| 6 | + | |
| 7 | +class OAuthSignatureMethodRsaSha1Test extends PHPUnit_Framework_TestCase { | |
| 8 | + private $method; | |
| 9 | + | |
| 10 | + public function setUp() { | |
| 11 | + $this->method = new Mock_OAuthSignatureMethod_RSA_SHA1(); | |
| 12 | + } | |
| 13 | + | |
| 14 | + public function testIdentifyAsRsaSha1() { | |
| 15 | + $this->assertEquals('RSA-SHA1', $this->method->get_name()); | |
| 16 | + } | |
| 17 | + | |
| 18 | + public function testBuildSignature() { | |
| 19 | + if( ! function_exists('openssl_get_privatekey') ) { | |
| 20 | + $this->markTestSkipped('OpenSSL not available, can\'t test RSA-SHA1 functionality'); | |
| 21 | + } | |
| 22 | + | |
| 23 | + // Tests taken from http://wiki.oauth.net/TestCases section 9.3 ("RSA-SHA1") | |
| 24 | + $request = new Mock_OAuthBaseStringRequest('GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacaction.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3D13917289812797014437%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D1196666512%26oauth_version%3D1.0%26size%3Doriginal'); | |
| 25 | + $consumer = new OAuthConsumer('dpf43f3p2l4k3l03', '__unused__'); | |
| 26 | + $token = NULL; | |
| 27 | + $signature = 'jvTp/wX1TYtByB1m+Pbyo0lnCOLIsyGCH7wke8AUs3BpnwZJtAuEJkvQL2/9n4s5wUmUl4aCI4BwpraNx4RtEXMe5qg5T1LVTGliMRpKasKsW//e+RinhejgCuzoH26dyF8iY2ZZ/5D1ilgeijhV/vBka5twt399mXwaYdCwFYE='; | |
| 28 | + $this->assertEquals($signature, $this->method->build_signature( $request, $consumer, $token) ); | |
| 29 | + } | |
| 30 | + | |
| 31 | + public function testVerifySignature() { | |
| 32 | + if( ! function_exists('openssl_get_privatekey') ) { | |
| 33 | + $this->markTestSkipped('OpenSSL not available, can\'t test RSA-SHA1 functionality'); | |
| 34 | + } | |
| 35 | + | |
| 36 | + // Tests taken from http://wiki.oauth.net/TestCases section 9.3 ("RSA-SHA1") | |
| 37 | + $request = new Mock_OAuthBaseStringRequest('GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacaction.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3D13917289812797014437%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D1196666512%26oauth_version%3D1.0%26size%3Doriginal'); | |
| 38 | + $consumer = new OAuthConsumer('dpf43f3p2l4k3l03', '__unused__'); | |
| 39 | + $token = NULL; | |
| 40 | + $signature = 'jvTp/wX1TYtByB1m+Pbyo0lnCOLIsyGCH7wke8AUs3BpnwZJtAuEJkvQL2/9n4s5wUmUl4aCI4BwpraNx4RtEXMe5qg5T1LVTGliMRpKasKsW//e+RinhejgCuzoH26dyF8iY2ZZ/5D1ilgeijhV/vBka5twt399mXwaYdCwFYE='; | |
| 41 | + $this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) ); | |
| 42 | + } | |
| 43 | +} | |
| 0 | 44 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +require_once 'common.php'; | |
| 4 | + | |
| 5 | +class OAuthTokenTest extends PHPUnit_Framework_TestCase { | |
| 6 | + public function testSerialize() { | |
| 7 | + $token = new OAuthToken('token', 'secret'); | |
| 8 | + $this->assertEquals('oauth_token=token&oauth_token_secret=secret', $token->to_string()); | |
| 9 | + | |
| 10 | + $token = new OAuthToken('token&', 'secret%'); | |
| 11 | + $this->assertEquals('oauth_token=token%26&oauth_token_secret=secret%25', $token->to_string()); | |
| 12 | + } | |
| 13 | + public function testConvertToString() { | |
| 14 | + $token = new OAuthToken('token', 'secret'); | |
| 15 | + $this->assertEquals('oauth_token=token&oauth_token_secret=secret', (string) $token); | |
| 16 | + | |
| 17 | + $token = new OAuthToken('token&', 'secret%'); | |
| 18 | + $this->assertEquals('oauth_token=token%26&oauth_token_secret=secret%25', (string) $token); | |
| 19 | + } | |
| 20 | +} | |
| 0 | 21 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,133 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +require_once dirname(__FILE__) . '/common.php'; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Tests of OAuthUtil | |
| 7 | + */ | |
| 8 | +class OAuthUtilTest extends PHPUnit_Framework_TestCase { | |
| 9 | + public function testUrlencode() { | |
| 10 | + // Tests taken from | |
| 11 | + // http://wiki.oauth.net/TestCases ("Parameter Encoding") | |
| 12 | + $this->assertEquals('abcABC123', OAuthUtil::urlencode_rfc3986('abcABC123')); | |
| 13 | + $this->assertEquals('-._~', OAuthUtil::urlencode_rfc3986('-._~')); | |
| 14 | + $this->assertEquals('%25', OAuthUtil::urlencode_rfc3986('%')); | |
| 15 | + $this->assertEquals('%2B', OAuthUtil::urlencode_rfc3986('+')); | |
| 16 | + $this->assertEquals('%0A', OAuthUtil::urlencode_rfc3986("\n")); | |
| 17 | + $this->assertEquals('%20', OAuthUtil::urlencode_rfc3986(' ')); | |
| 18 | + $this->assertEquals('%7F', OAuthUtil::urlencode_rfc3986("\x7F")); | |
| 19 | + //$this->assertEquals('%C2%80', OAuthUtil::urlencode_rfc3986("\x00\x80")); | |
| 20 | + //$this->assertEquals('%E3%80%81', OAuthUtil::urlencode_rfc3986("\x30\x01")); | |
| 21 | + | |
| 22 | + // Last two checks disabled because of lack of UTF-8 support, or lack | |
| 23 | + // of knowledge from me (morten.fangel) on how to use it properly.. | |
| 24 | + | |
| 25 | + // A few tests to ensure code-coverage | |
| 26 | + $this->assertEquals( '', OAuthUtil::urlencode_rfc3986(NULL)); | |
| 27 | + $this->assertEquals( '', OAuthUtil::urlencode_rfc3986(new stdClass())); | |
| 28 | + } | |
| 29 | + | |
| 30 | + public function testUrldecode() { | |
| 31 | + // Tests taken from | |
| 32 | + // http://wiki.oauth.net/TestCases ("Parameter Encoding") | |
| 33 | + $this->assertEquals('abcABC123', OAuthUtil::urldecode_rfc3986('abcABC123')); | |
| 34 | + $this->assertEquals('-._~', OAuthUtil::urldecode_rfc3986('-._~')); | |
| 35 | + $this->assertEquals('%', OAuthUtil::urldecode_rfc3986('%25')); | |
| 36 | + $this->assertEquals('+', OAuthUtil::urldecode_rfc3986('%2B')); | |
| 37 | + $this->assertEquals("\n", OAuthUtil::urldecode_rfc3986('%0A')); | |
| 38 | + $this->assertEquals(' ', OAuthUtil::urldecode_rfc3986('%20')); | |
| 39 | + $this->assertEquals("\x7F", OAuthUtil::urldecode_rfc3986('%7F')); | |
| 40 | + //$this->assertEquals("\x00\x80", OAuthUtil::urldecode_rfc3986('%C2%80')); | |
| 41 | + //$this->assertEquals("\x30\x01", OAuthUtil::urldecode_rfc3986('%E3%80%81')); | |
| 42 | + | |
| 43 | + // Last two checks disabled because of lack of UTF-8 support, or lack | |
| 44 | + // of knowledge from me (morten.fangel) on how to use it properly.. | |
| 45 | + } | |
| 46 | + | |
| 47 | + public function testParseParameter() { | |
| 48 | + // Tests taken from | |
| 49 | + // http://wiki.oauth.net/TestCases ("Normalize Request Parameters") | |
| 50 | + | |
| 51 | + $this->assertEquals( | |
| 52 | + array('name'=>''), | |
| 53 | + OAuthUtil::parse_parameters('name') | |
| 54 | + ); | |
| 55 | + $this->assertEquals( | |
| 56 | + array('a'=>'b'), | |
| 57 | + OAuthUtil::parse_parameters('a=b') | |
| 58 | + ); | |
| 59 | + $this->assertEquals( | |
| 60 | + array('a'=>'b','c'=>'d'), | |
| 61 | + OAuthUtil::parse_parameters('a=b&c=d') | |
| 62 | + ); | |
| 63 | + $this->assertEquals( | |
| 64 | + array('a'=>array('x!y','x y')), | |
| 65 | + OAuthUtil::parse_parameters('a=x!y&a=x+y') | |
| 66 | + ); | |
| 67 | + $this->assertEquals( | |
| 68 | + array('x!y'=>'a', 'x' =>'a'), | |
| 69 | + OAuthUtil::parse_parameters('x!y=a&x=a') | |
| 70 | + ); | |
| 71 | + } | |
| 72 | + | |
| 73 | + public function testBuildHttpQuery() { | |
| 74 | + // Tests taken from | |
| 75 | + // http://wiki.oauth.net/TestCases ("Normalize Request Parameters") | |
| 76 | + $this->assertEquals( | |
| 77 | + 'name=', | |
| 78 | + OAuthUtil::build_http_query(array('name'=>'')) | |
| 79 | + ); | |
| 80 | + $this->assertEquals( | |
| 81 | + 'a=b', | |
| 82 | + OAuthUtil::build_http_query(array('a'=>'b')) | |
| 83 | + ); | |
| 84 | + $this->assertEquals( | |
| 85 | + 'a=b&c=d', | |
| 86 | + OAuthUtil::build_http_query(array('a'=>'b','c'=>'d')) | |
| 87 | + ); | |
| 88 | + $this->assertEquals( | |
| 89 | + 'a=x%20y&a=x%21y', | |
| 90 | + OAuthUtil::build_http_query(array('a'=>array('x!y','x y'))) | |
| 91 | + ); | |
| 92 | + $this->assertEquals( | |
| 93 | + 'x=a&x%21y=a', | |
| 94 | + OAuthUtil::build_http_query(array('x!y'=>'a', 'x' =>'a')) | |
| 95 | + ); | |
| 96 | + | |
| 97 | + // Test taken from the Spec 9.1.1 | |
| 98 | + $this->assertEquals( | |
| 99 | + 'a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t', | |
| 100 | + OAuthUtil::build_http_query(array('a'=>'1', 'c' =>'hi there', 'f'=>array(25, 50, 'a'), 'z'=>array('p','t'))) | |
| 101 | + ); | |
| 102 | + } | |
| 103 | + | |
| 104 | + public function testSplitHeader() { | |
| 105 | + $this->assertEquals( | |
| 106 | + array('oauth_foo'=>'bar','oauth_baz'=>'bla,rgh'), | |
| 107 | + OAuthUtil::split_header('OAuth realm="",oauth_foo=bar,oauth_baz="bla,rgh"') | |
| 108 | + ); | |
| 109 | + $this->assertEquals( | |
| 110 | + array(), | |
| 111 | + OAuthUtil::split_header('OAuth realm="",foo=bar,baz="bla,rgh"') | |
| 112 | + ); | |
| 113 | + $this->assertEquals( | |
| 114 | + array('foo'=>'bar', 'baz'=>'bla,rgh'), | |
| 115 | + OAuthUtil::split_header('OAuth realm="",foo=bar,baz="bla,rgh"', false) | |
| 116 | + ); | |
| 117 | + $this->assertEquals( | |
| 118 | + array('oauth_foo' => 'hi there'), | |
| 119 | + OAuthUtil::split_header('OAuth realm="",oauth_foo=hi+there,foo=bar,baz="bla,rgh"') | |
| 120 | + ); | |
| 121 | + | |
| 122 | + } | |
| 123 | + | |
| 124 | + public function testGetHeaders() { | |
| 125 | + if (function_exists('apache_request_headers')) { | |
| 126 | + $this->markTestSkipped('We assume the apache module is well tested. Since this module is present, no need testing our suplement'); | |
| 127 | + } | |
| 128 | + | |
| 129 | + $_SERVER['HTTP_HOST'] = 'foo'; | |
| 130 | + $_SERVER['HTTP_X_WHATEVER'] = 'bar'; | |
| 131 | + $this->assertEquals( array('Host'=>'foo', 'X-Whatever'=>'bar'), OAuthUtil::get_headers() ); | |
| 132 | + } | |
| 133 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,62 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +require dirname(__FILE__).'/../OAuth.php'; | |
| 4 | +require_once 'PHPUnit/Framework.php'; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * A simple utils class for methods needed | |
| 8 | + * during some of the tests | |
| 9 | + */ | |
| 10 | +class OAuthTestUtils { | |
| 11 | + private static function reset_request_vars() { | |
| 12 | + $_SERVER = array(); | |
| 13 | + $_POST = array(); | |
| 14 | + $_GET = array(); | |
| 15 | + } | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * Populates $_{SERVER,GET,POST} and whatever environment-variables needed to test everything.. | |
| 19 | + * | |
| 20 | + * @param string $method GET or POST | |
| 21 | + * @param string $uri What URI is the request to (eg http://example.com/foo?bar=baz) | |
| 22 | + * @param string $post_data What should the post-data be | |
| 23 | + * @param string $auth_header What to set the Authorization header to | |
| 24 | + */ | |
| 25 | + public static function build_request( $method, $uri, $post_data = '', $auth_header = '' ) { | |
| 26 | + self::reset_request_vars(); | |
| 27 | + | |
| 28 | + $method = strtoupper($method); | |
| 29 | + | |
| 30 | + $parts = parse_url($uri); | |
| 31 | + | |
| 32 | + $port = @$parts['port']; | |
| 33 | + $scheme = $parts['scheme']; | |
| 34 | + $host = $parts['host']; | |
| 35 | + $path = @$parts['path']; | |
| 36 | + $query = @$parts['query']; | |
| 37 | + | |
| 38 | + $port or $port = ($scheme == 'https') ? '443' : '80'; | |
| 39 | + | |
| 40 | + if( $scheme == 'https') { | |
| 41 | + $_SERVER['HTTPS'] = 'on'; | |
| 42 | + } | |
| 43 | + | |
| 44 | + $_SERVER['REQUEST_METHOD'] = $method; | |
| 45 | + $_SERVER['HTTP_HOST'] = $host; | |
| 46 | + $_SERVER['SERVER_PORT'] = $port; | |
| 47 | + $_SERVER['SCRIPT_NAME'] = $path; | |
| 48 | + $_SERVER['REQUEST_URI'] = $path . '?' . $query; | |
| 49 | + $_SERVER['QUERY_STRING'] = $query.''; | |
| 50 | + parse_str($query, $_GET); | |
| 51 | + | |
| 52 | + if( $method == 'POST' ) { | |
| 53 | + $_SERVER['HTTP_CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; | |
| 54 | + $_POST = parse_str($post_data); | |
| 55 | + OAuthRequest::$POST_INPUT = 'data:application/x-www-form-urlencoded,'.$post_data; | |
| 56 | + } | |
| 57 | + | |
| 58 | + if( $auth_header != '' ) { | |
| 59 | + $_SERVER['HTTP_AUTHORIZATION'] = $auth_header; | |
| 60 | + } | |
| 61 | + } | |
| 62 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | +<?php | |
| 2 | +# Logging in with Google accounts requires setting special identity, so this example shows how to do it. | |
| 3 | +require 'openid.php'; | |
| 4 | +try { | |
| 5 | + $openid = new LightOpenID; | |
| 6 | + if(!$openid->mode) { | |
| 7 | + if(isset($_GET['login'])) { | |
| 8 | + $openid->identity = 'https://www.google.com/accounts/o8/id'; | |
| 9 | + header('Location: ' . $openid->authUrl()); | |
| 10 | + } | |
| 11 | +?> | |
| 12 | +<form action="?login" method="post"> | |
| 13 | + <button>Login with Google</button> | |
| 14 | +</form> | |
| 15 | +<?php | |
| 16 | + } elseif($openid->mode == 'cancel') { | |
| 17 | + echo 'User has canceled authentication!'; | |
| 18 | + } else { | |
| 19 | + echo 'User ' . ($openid->validate() ? $openid->identity . ' has ' : 'has not ') . 'logged in.'; | |
| 20 | + } | |
| 21 | +} catch(ErrorException $e) { | |
| 22 | + echo $e->getMessage(); | |
| 23 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,132 @@ |
| 1 | +<html> | |
| 2 | +<style> | |
| 3 | +body | |
| 4 | +{background-color:white;font-family: Verdana, Arial, Helvetica, sans-serif;font-size: 12px;margin: 10px} | |
| 5 | +img | |
| 6 | +{cursor:pointer;border:1px solid gray;} | |
| 7 | +</style> | |
| 8 | +<?php | |
| 9 | +//http://localhost/i3geo/pacotes/openid/login.php?g_sid=dqpk71kh6ei121s4u5g1qb9vi1 | |
| 10 | +session_name("openid"); | |
| 11 | +session_start(); | |
| 12 | +include_once("../../ms_configura.php"); | |
| 13 | +if($_SESSION["openid"] == false) | |
| 14 | +{ | |
| 15 | + $dadosurl = array_merge($_GET,$_POST); | |
| 16 | + if(!empty($dadosurl["erro"])){ | |
| 17 | + echo "<span style=color:red >Ocorreu algum erro</span><br><br>"; | |
| 18 | + } | |
| 19 | + | |
| 20 | +} | |
| 21 | +require 'openid.php'; | |
| 22 | +try { | |
| 23 | + $openid = new LightOpenID; | |
| 24 | + if(!$openid->mode && $_SESSION["openid"] == false) { | |
| 25 | + if(isset($dadosurl['openid_identifier']) && empty($dadosurl["erro"])) { | |
| 26 | + $openid->identity = $dadosurl['openid_identifier']; | |
| 27 | + header('Location: ' . $openid->authUrl()); | |
| 28 | + } | |
| 29 | +?> | |
| 30 | + | |
| 31 | +<body> | |
| 32 | +<div id=corpo > | |
| 33 | +<a href="http://openid.net/" target=_blank ><img style="border:0px solid gray;" src="../../imagens/redes_openid.png"/></a> | |
| 34 | +<a href="http://oauth.net/" target=_blank ><img width=135px style="border:0px solid gray;" src="../../imagens/redes_oauth.png"/></a><br> | |
| 35 | + | |
| 36 | +Utilize uma das redes abaixo para confirmar sua identidade<br><br> | |
| 37 | +<img src="../../imagens/redes_google.png" onclick="submete('google')"/> | |
| 38 | +<?php | |
| 39 | +if(is_array($facebookoauth)) | |
| 40 | +{echo '<img src="../../imagens/redes_facebook.png" onclick="submete(\'facebook\')"/> ';} | |
| 41 | +?> | |
| 42 | +<img src="../../imagens/redes_myspace.png" onclick="submete('myspace')"/> | |
| 43 | +<?php | |
| 44 | +if(is_array($twitteroauth)) | |
| 45 | +{echo '<img src="../../imagens/redes_twitter.png" onclick="submete(\'twitter\')"/> ';} | |
| 46 | +?> | |
| 47 | +<?php | |
| 48 | +if(is_array($linkedinoauth)) | |
| 49 | +{echo '<img src="../../imagens/redes_linkedin.png" onclick="submete(\'linkedin\')"/> ';} | |
| 50 | +?> | |
| 51 | +<img src="../../imagens/redes_windowslive.png"/> | |
| 52 | +<img src="../../imagens/redes_wordpress.png" onclick="submete('wordpress')"/> | |
| 53 | +<img src="../../imagens/redes_blogger.png" onclick="submete('blogger')"/> | |
| 54 | +</div> | |
| 55 | + | |
| 56 | +<script> | |
| 57 | +function submete(quem){ | |
| 58 | + if(quem == "linkedin") | |
| 59 | + { | |
| 60 | + var url = "<?php echo $_SESSION["locaplic"]; ?>/pacotes/linkedinoauth/index.php"; | |
| 61 | + } | |
| 62 | + if(quem == "google") | |
| 63 | + { | |
| 64 | + var u = window.prompt("Usuário",""); | |
| 65 | + if(!u){return;} | |
| 66 | + var url = 'http://www.google.com/profiles/'+u; | |
| 67 | + } | |
| 68 | + if(quem == "myspace") | |
| 69 | + { | |
| 70 | + var u = window.prompt("Usuário",""); | |
| 71 | + if(!u){return;} | |
| 72 | + var url = 'http://myspace.com/'+u; | |
| 73 | + } | |
| 74 | + if(quem == "twitter") | |
| 75 | + { | |
| 76 | + var url = "<?php echo $_SESSION["locaplic"]; ?>/pacotes/twitteroauth/redirect.php"; | |
| 77 | + } | |
| 78 | + if(quem == "wordpress") | |
| 79 | + { | |
| 80 | + var u = window.prompt("Usuário",""); | |
| 81 | + if(!u){return;} | |
| 82 | + var url = 'http://'+u+'wordpress.com'; | |
| 83 | + } | |
| 84 | + if(quem == "blogger") | |
| 85 | + { | |
| 86 | + var u = window.prompt("Usuário",""); | |
| 87 | + if(!u){return;} | |
| 88 | + var url = 'http://'+u+'.blogspot.com'; | |
| 89 | + } | |
| 90 | + if(quem == "facebook") | |
| 91 | + { | |
| 92 | + var url = "<?php echo $_SESSION["locaplic"]; ?>/pacotes/facebookoauth/index.php"; | |
| 93 | + } | |
| 94 | + if(quem == "google" || quem == "myspace" || quem == "wordpress" || quem == "blogger"){ | |
| 95 | + url = "login.php?&usuario="+u+"&openid_identifier="+url+"&servico="+quem+"&imagem=&nome="+u; | |
| 96 | + } | |
| 97 | + document.getElementById("corpo").style.display = "none"; | |
| 98 | + document.body.innerHTML += "Aguarde..."; | |
| 99 | + window.location.href = url; | |
| 100 | +} | |
| 101 | +</script> | |
| 102 | +<?php | |
| 103 | + } elseif($openid->mode == 'cancel') { | |
| 104 | + echo 'User has canceled authentication!'; | |
| 105 | + } else { | |
| 106 | + if($_SESSION["openidservico"] != "twitter" && $_SESSION["openidservico"] != "facebook" && $_SESSION["openidservico"] != "linkedin"){ | |
| 107 | + $valido = $openid->validate(); | |
| 108 | + $_SESSION["openid"] = false; | |
| 109 | + if($valido){ | |
| 110 | + $_SESSION["openid"] = true; | |
| 111 | + $_SESSION["openidurl"] = $dadosurl["openid_identifier"]; | |
| 112 | + $_SESSION["openidusuario"] = $dadosurl["usuario"]; | |
| 113 | + $_SESSION["openidservico"] = $dadosurl["servico"]; | |
| 114 | + $_SESSION["openidimagem"] = $dadosurl["imagem"]; | |
| 115 | + $_SESSION["openidnome"] = $dadosurl["nome"]; | |
| 116 | + } | |
| 117 | + } | |
| 118 | + else{ | |
| 119 | + $valido = $_SESSION["openid"]; | |
| 120 | + } | |
| 121 | + if($valido){ | |
| 122 | + header('Location: ' . $_SESSION["urlVolta"]); | |
| 123 | + } | |
| 124 | + if(!$valido){ | |
| 125 | + $url = "login.php?login&erro=ok"; | |
| 126 | + header('Location: ' . $url); | |
| 127 | + } | |
| 128 | + } | |
| 129 | +} catch(ErrorException $e) { | |
| 130 | + echo $e->getMessage(); | |
| 131 | +} | |
| 132 | +?> | |
| 0 | 133 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,743 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * This class provides a simple interface for OpenID (1.1 and 2.0) authentication. | |
| 4 | + * Supports Yadis discovery. | |
| 5 | + * The authentication process is stateless/dumb. | |
| 6 | + * | |
| 7 | + * Usage: | |
| 8 | + * Sign-on with OpenID is a two step process: | |
| 9 | + * Step one is authentication with the provider: | |
| 10 | + * <code> | |
| 11 | + * $openid = new LightOpenID; | |
| 12 | + * $openid->identity = 'ID supplied by user'; | |
| 13 | + * header('Location: ' . $openid->authUrl()); | |
| 14 | + * </code> | |
| 15 | + * The provider then sends various parameters via GET, one of them is openid_mode. | |
| 16 | + * Step two is verification: | |
| 17 | + * <code> | |
| 18 | + * if ($this->data['openid_mode']) { | |
| 19 | + * $openid = new LightOpenID; | |
| 20 | + * echo $openid->validate() ? 'Logged in.' : 'Failed'; | |
| 21 | + * } | |
| 22 | + * </code> | |
| 23 | + * | |
| 24 | + * Optionally, you can set $returnUrl and $realm (or $trustRoot, which is an alias). | |
| 25 | + * The default values for those are: | |
| 26 | + * $openid->realm = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; | |
| 27 | + * $openid->returnUrl = $openid->realm . $_SERVER['REQUEST_URI']; | |
| 28 | + * If you don't know their meaning, refer to any openid tutorial, or specification. Or just guess. | |
| 29 | + * | |
| 30 | + * AX and SREG extensions are supported. | |
| 31 | + * To use them, specify $openid->required and/or $openid->optional before calling $openid->authUrl(). | |
| 32 | + * These are arrays, with values being AX schema paths (the 'path' part of the URL). | |
| 33 | + * For example: | |
| 34 | + * $openid->required = array('namePerson/friendly', 'contact/email'); | |
| 35 | + * $openid->optional = array('namePerson/first'); | |
| 36 | + * If the server supports only SREG or OpenID 1.1, these are automaticaly | |
| 37 | + * mapped to SREG names, so that user doesn't have to know anything about the server. | |
| 38 | + * | |
| 39 | + * To get the values, use $openid->getAttributes(). | |
| 40 | + * | |
| 41 | + * | |
| 42 | + * The library requires PHP >= 5.1.2 with curl or http/https stream wrappers enabled.. | |
| 43 | + * @author Mewp | |
| 44 | + * @copyright Copyright (c) 2010, Mewp | |
| 45 | + * @license http://www.opensource.org/licenses/mit-license.php MIT | |
| 46 | + */ | |
| 47 | +class LightOpenID | |
| 48 | +{ | |
| 49 | + public $returnUrl | |
| 50 | + , $g_sid | |
| 51 | + , $required = array() | |
| 52 | + , $optional = array() | |
| 53 | + , $verify_peer = null | |
| 54 | + , $capath = null | |
| 55 | + , $cainfo = null; | |
| 56 | + private $identity, $claimed_id; | |
| 57 | + protected $server, $version, $trustRoot, $aliases, $identifier_select = false | |
| 58 | + , $ax = false, $sreg = false, $data; | |
| 59 | + static protected $ax_to_sreg = array( | |
| 60 | + 'namePerson/friendly' => 'nickname', | |
| 61 | + 'contact/email' => 'email', | |
| 62 | + 'namePerson' => 'fullname', | |
| 63 | + 'birthDate' => 'dob', | |
| 64 | + 'person/gender' => 'gender', | |
| 65 | + 'contact/postalCode/home' => 'postcode', | |
| 66 | + 'contact/country/home' => 'country', | |
| 67 | + 'pref/language' => 'language', | |
| 68 | + 'pref/timezone' => 'timezone', | |
| 69 | + ); | |
| 70 | + | |
| 71 | + function __construct() | |
| 72 | + { | |
| 73 | + $this->trustRoot = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; | |
| 74 | + $uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?'); | |
| 75 | + $this->returnUrl = $this->trustRoot . $uri; | |
| 76 | + | |
| 77 | + $this->data = $_POST + $_GET; # OPs may send data as POST or GET. | |
| 78 | + } | |
| 79 | + | |
| 80 | + function __set($name, $value) | |
| 81 | + { | |
| 82 | + switch ($name) { | |
| 83 | + case 'identity': | |
| 84 | + if (strlen($value = trim((String) $value))) { | |
| 85 | + if (preg_match('#^xri:/*#i', $value, $m)) { | |
| 86 | + $value = substr($value, strlen($m[0])); | |
| 87 | + } elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) { | |
| 88 | + $value = "http://$value"; | |
| 89 | + } | |
| 90 | + if (preg_match('#^https?://[^/]+$#i', $value, $m)) { | |
| 91 | + $value .= '/'; | |
| 92 | + } | |
| 93 | + } | |
| 94 | + $this->$name = $this->claimed_id = $value; | |
| 95 | + break; | |
| 96 | + case 'trustRoot': | |
| 97 | + case 'realm': | |
| 98 | + $this->trustRoot = trim($value); | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + function __get($name) | |
| 103 | + { | |
| 104 | + switch ($name) { | |
| 105 | + case 'identity': | |
| 106 | + # We return claimed_id instead of identity, | |
| 107 | + # because the developer should see the claimed identifier, | |
| 108 | + # i.e. what he set as identity, not the op-local identifier (which is what we verify) | |
| 109 | + return $this->claimed_id; | |
| 110 | + case 'trustRoot': | |
| 111 | + case 'realm': | |
| 112 | + return $this->trustRoot; | |
| 113 | + case 'mode': | |
| 114 | + return empty($this->data['openid_mode']) ? null : $this->data['openid_mode']; | |
| 115 | + } | |
| 116 | + } | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * Checks if the server specified in the url exists. | |
| 120 | + * | |
| 121 | + * @param $url url to check | |
| 122 | + * @return true, if the server exists; false otherwise | |
| 123 | + */ | |
| 124 | + function hostExists($url) | |
| 125 | + { | |
| 126 | + if (strpos($url, '/') === false) { | |
| 127 | + $server = $url; | |
| 128 | + } else { | |
| 129 | + $server = @parse_url($url, PHP_URL_HOST); | |
| 130 | + } | |
| 131 | + | |
| 132 | + if (!$server) { | |
| 133 | + return false; | |
| 134 | + } | |
| 135 | + | |
| 136 | + return !!gethostbynamel($server); | |
| 137 | + } | |
| 138 | + | |
| 139 | + protected function request_curl($url, $method='GET', $params=array()) | |
| 140 | + { | |
| 141 | + $s = PHP_SHLIB_SUFFIX; | |
| 142 | + if(!function_exists('curl_init')) | |
| 143 | + {@dl( 'php_curl'.'.'.$s );} | |
| 144 | + if(!function_exists('curl_init')) | |
| 145 | + {echo "curl não instalado";} | |
| 146 | + $params = http_build_query($params, '', '&'); | |
| 147 | + $curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : '')); | |
| 148 | + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); | |
| 149 | + curl_setopt($curl, CURLOPT_HEADER, false); | |
| 150 | + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); | |
| 151 | + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
| 152 | + curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*')); | |
| 153 | + | |
| 154 | + if($this->verify_peer !== null) { | |
| 155 | + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); | |
| 156 | + if($this->capath) { | |
| 157 | + curl_setopt($curl, CURLOPT_CAPATH, $this->capath); | |
| 158 | + } | |
| 159 | + | |
| 160 | + if($this->cainfo) { | |
| 161 | + curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo); | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 165 | + if ($method == 'POST') { | |
| 166 | + curl_setopt($curl, CURLOPT_POST, true); | |
| 167 | + curl_setopt($curl, CURLOPT_POSTFIELDS, $params); | |
| 168 | + } elseif ($method == 'HEAD') { | |
| 169 | + curl_setopt($curl, CURLOPT_HEADER, true); | |
| 170 | + curl_setopt($curl, CURLOPT_NOBODY, true); | |
| 171 | + } else { | |
| 172 | + curl_setopt($curl, CURLOPT_HTTPGET, true); | |
| 173 | + } | |
| 174 | + $response = curl_exec($curl); | |
| 175 | + if($method == 'HEAD') { | |
| 176 | + $headers = array(); | |
| 177 | + foreach(explode("\n", $response) as $header) { | |
| 178 | + $pos = strpos($header,':'); | |
| 179 | + $name = strtolower(trim(substr($header, 0, $pos))); | |
| 180 | + $headers[$name] = trim(substr($header, $pos+1)); | |
| 181 | + } | |
| 182 | + | |
| 183 | + # Updating claimed_id in case of redirections. | |
| 184 | + $effective_url = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL); | |
| 185 | + if($effective_url != $url) { | |
| 186 | + $this->identity = $this->claimed_id = $effective_url; | |
| 187 | + } | |
| 188 | + | |
| 189 | + return $headers; | |
| 190 | + } | |
| 191 | + | |
| 192 | + if (curl_errno($curl)) { | |
| 193 | + throw new ErrorException(curl_error($curl), curl_errno($curl)); | |
| 194 | + } | |
| 195 | + return $response; | |
| 196 | + } | |
| 197 | + | |
| 198 | + protected function request_streams($url, $method='GET', $params=array()) | |
| 199 | + { | |
| 200 | + if(!$this->hostExists($url)) { | |
| 201 | + throw new ErrorException('Invalid request.'); | |
| 202 | + } | |
| 203 | + | |
| 204 | + $params = http_build_query($params, '', '&'); | |
| 205 | + switch($method) { | |
| 206 | + case 'GET': | |
| 207 | + $opts = array( | |
| 208 | + 'http' => array( | |
| 209 | + 'method' => 'GET', | |
| 210 | + 'header' => 'Accept: application/xrds+xml, */*', | |
| 211 | + 'ignore_errors' => true, | |
| 212 | + ) | |
| 213 | + ); | |
| 214 | + $url = $url . ($params ? '?' . $params : ''); | |
| 215 | + break; | |
| 216 | + case 'POST': | |
| 217 | + $opts = array( | |
| 218 | + 'http' => array( | |
| 219 | + 'method' => 'POST', | |
| 220 | + 'header' => 'Content-type: application/x-www-form-urlencoded', | |
| 221 | + 'content' => $params, | |
| 222 | + 'ignore_errors' => true, | |
| 223 | + ) | |
| 224 | + ); | |
| 225 | + break; | |
| 226 | + case 'HEAD': | |
| 227 | + # We want to send a HEAD request, | |
| 228 | + # but since get_headers doesn't accept $context parameter, | |
| 229 | + # we have to change the defaults. | |
| 230 | + $default = stream_context_get_options(stream_context_get_default()); | |
| 231 | + stream_context_get_default( | |
| 232 | + array('http' => array( | |
| 233 | + 'method' => 'HEAD', | |
| 234 | + 'header' => 'Accept: application/xrds+xml, */*', | |
| 235 | + 'ignore_errors' => true, | |
| 236 | + )) | |
| 237 | + ); | |
| 238 | + | |
| 239 | + $url = $url . ($params ? '?' . $params : ''); | |
| 240 | + $headers_tmp = get_headers ($url); | |
| 241 | + if(!$headers_tmp) { | |
| 242 | + return array(); | |
| 243 | + } | |
| 244 | + | |
| 245 | + # Parsing headers. | |
| 246 | + $headers = array(); | |
| 247 | + foreach($headers_tmp as $header) { | |
| 248 | + $pos = strpos($header,':'); | |
| 249 | + $name = strtolower(trim(substr($header, 0, $pos))); | |
| 250 | + $headers[$name] = trim(substr($header, $pos+1)); | |
| 251 | + | |
| 252 | + # Following possible redirections. The point is just to have | |
| 253 | + # claimed_id change with them, because get_headers() will | |
| 254 | + # follow redirections automatically. | |
| 255 | + # We ignore redirections with relative paths. | |
| 256 | + # If any known provider uses them, file a bug report. | |
| 257 | + if($name == 'location') { | |
| 258 | + if(strpos($headers[$name], 'http') === 0) { | |
| 259 | + $this->identity = $this->claimed_id = $headers[$name]; | |
| 260 | + } elseif($headers[$name][0] == '/') { | |
| 261 | + $parsed_url = parse_url($this->claimed_id); | |
| 262 | + $this->identity = | |
| 263 | + $this->claimed_id = $parsed_url['scheme'] . '://' | |
| 264 | + . $parsed_url['host'] | |
| 265 | + . $headers[$name]; | |
| 266 | + } | |
| 267 | + } | |
| 268 | + } | |
| 269 | + | |
| 270 | + # And restore them. | |
| 271 | + stream_context_get_default($default); | |
| 272 | + //var_dump($headers);exit; | |
| 273 | + return $headers; | |
| 274 | + } | |
| 275 | + | |
| 276 | + if($this->verify_peer) { | |
| 277 | + $opts += array('ssl' => array( | |
| 278 | + 'verify_peer' => true, | |
| 279 | + 'capath' => $this->capath, | |
| 280 | + 'cafile' => $this->cainfo, | |
| 281 | + )); | |
| 282 | + } | |
| 283 | + | |
| 284 | + $context = stream_context_create ($opts); | |
| 285 | + | |
| 286 | + return file_get_contents($url, false, $context); | |
| 287 | + } | |
| 288 | + | |
| 289 | + protected function request($url, $method='GET', $params=array()) | |
| 290 | + { | |
| 291 | + if(function_exists('curl_init') && !ini_get('safe_mode')) { | |
| 292 | + return $this->request_curl($url, $method, $params); | |
| 293 | + } | |
| 294 | + return $this->request_streams($url, $method, $params); | |
| 295 | + } | |
| 296 | + | |
| 297 | + protected function build_url($url, $parts) | |
| 298 | + { | |
| 299 | + if (isset($url['query'], $parts['query'])) { | |
| 300 | + $parts['query'] = $url['query'] . '&' . $parts['query']; | |
| 301 | + } | |
| 302 | + | |
| 303 | + $url = $parts + $url; | |
| 304 | + $url = $url['scheme'] . '://' | |
| 305 | + . (empty($url['username'])?'' | |
| 306 | + :(empty($url['password'])? "{$url['username']}@" | |
| 307 | + :"{$url['username']}:{$url['password']}@")) | |
| 308 | + . $url['host'] | |
| 309 | + . (empty($url['port'])?'':":{$url['port']}") | |
| 310 | + . (empty($url['path'])?'':$url['path']) | |
| 311 | + . (empty($url['query'])?'':"?{$url['query']}") | |
| 312 | + . (empty($url['fragment'])?'':"#{$url['fragment']}"); | |
| 313 | + return $url; | |
| 314 | + } | |
| 315 | + | |
| 316 | + /** | |
| 317 | + * Helper function used to scan for <meta>/<link> tags and extract information | |
| 318 | + * from them | |
| 319 | + */ | |
| 320 | + protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName) | |
| 321 | + { | |
| 322 | + preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1); | |
| 323 | + preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2); | |
| 324 | + | |
| 325 | + $result = array_merge($matches1[1], $matches2[1]); | |
| 326 | + return empty($result)?false:$result[0]; | |
| 327 | + } | |
| 328 | + | |
| 329 | + /** | |
| 330 | + * Performs Yadis and HTML discovery. Normally not used. | |
| 331 | + * @param $url Identity URL. | |
| 332 | + * @return String OP Endpoint (i.e. OpenID provider address). | |
| 333 | + * @throws ErrorException | |
| 334 | + */ | |
| 335 | + function discover($url) | |
| 336 | + { | |
| 337 | + if (!$url) throw new ErrorException('No identity supplied.'); | |
| 338 | + # Use xri.net proxy to resolve i-name identities | |
| 339 | + if (!preg_match('#^https?:#', $url)) { | |
| 340 | + $url = "https://xri.net/$url"; | |
| 341 | + } | |
| 342 | + | |
| 343 | + # We save the original url in case of Yadis discovery failure. | |
| 344 | + # It can happen when we'll be lead to an XRDS document | |
| 345 | + # which does not have any OpenID2 services. | |
| 346 | + $originalUrl = $url; | |
| 347 | + | |
| 348 | + # A flag to disable yadis discovery in case of failure in headers. | |
| 349 | + $yadis = true; | |
| 350 | + | |
| 351 | + # We'll jump a maximum of 5 times, to avoid endless redirections. | |
| 352 | + for ($i = 0; $i < 5; $i ++) { | |
| 353 | + if ($yadis) { | |
| 354 | + $headers = $this->request($url, 'HEAD'); | |
| 355 | + | |
| 356 | + $next = false; | |
| 357 | + if (isset($headers['x-xrds-location'])) { | |
| 358 | + $url = $this->build_url(parse_url($url), parse_url(trim($headers['x-xrds-location']))); | |
| 359 | + $next = true; | |
| 360 | + } | |
| 361 | + | |
| 362 | + if (isset($headers['content-type']) | |
| 363 | + && (strpos($headers['content-type'], 'application/xrds+xml') !== false | |
| 364 | + || strpos($headers['content-type'], 'text/xml') !== false) | |
| 365 | + ) { | |
| 366 | + # Apparently, some providers return XRDS documents as text/html. | |
| 367 | + # While it is against the spec, allowing this here shouldn't break | |
| 368 | + # compatibility with anything. | |
| 369 | + # --- | |
| 370 | + # Found an XRDS document, now let's find the server, and optionally delegate. | |
| 371 | + $content = $this->request($url, 'GET'); | |
| 372 | + | |
| 373 | + preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m); | |
| 374 | + foreach($m[1] as $content) { | |
| 375 | + $content = ' ' . $content; # The space is added, so that strpos doesn't return 0. | |
| 376 | + | |
| 377 | + # OpenID 2 | |
| 378 | + $ns = preg_quote('http://specs.openid.net/auth/2.0/'); | |
| 379 | + if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) { | |
| 380 | + if ($type[1] == 'server') $this->identifier_select = true; | |
| 381 | + | |
| 382 | + preg_match('#<URI.*?>(.*)</URI>#', $content, $server); | |
| 383 | + preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate); | |
| 384 | + if (empty($server)) { | |
| 385 | + return false; | |
| 386 | + } | |
| 387 | + # Does the server advertise support for either AX or SREG? | |
| 388 | + $this->ax = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>'); | |
| 389 | + $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') | |
| 390 | + || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); | |
| 391 | + | |
| 392 | + $server = $server[1]; | |
| 393 | + if (isset($delegate[2])) $this->identity = trim($delegate[2]); | |
| 394 | + $this->version = 2; | |
| 395 | + | |
| 396 | + $this->server = $server; | |
| 397 | + return $server; | |
| 398 | + } | |
| 399 | + | |
| 400 | + # OpenID 1.1 | |
| 401 | + $ns = preg_quote('http://openid.net/signon/1.1'); | |
| 402 | + if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) { | |
| 403 | + | |
| 404 | + preg_match('#<URI.*?>(.*)</URI>#', $content, $server); | |
| 405 | + preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate); | |
| 406 | + if (empty($server)) { | |
| 407 | + return false; | |
| 408 | + } | |
| 409 | + # AX can be used only with OpenID 2.0, so checking only SREG | |
| 410 | + $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') | |
| 411 | + || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); | |
| 412 | + | |
| 413 | + $server = $server[1]; | |
| 414 | + if (isset($delegate[1])) $this->identity = $delegate[1]; | |
| 415 | + $this->version = 1; | |
| 416 | + | |
| 417 | + $this->server = $server; | |
| 418 | + return $server; | |
| 419 | + } | |
| 420 | + } | |
| 421 | + | |
| 422 | + $next = true; | |
| 423 | + $yadis = false; | |
| 424 | + $url = $originalUrl; | |
| 425 | + $content = null; | |
| 426 | + break; | |
| 427 | + } | |
| 428 | + if ($next) continue; | |
| 429 | + | |
| 430 | + # There are no relevant information in headers, so we search the body. | |
| 431 | + $content = $this->request($url, 'GET'); | |
| 432 | + $location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content'); | |
| 433 | + if ($location) { | |
| 434 | + $url = $this->build_url(parse_url($url), parse_url($location)); | |
| 435 | + continue; | |
| 436 | + } | |
| 437 | + } | |
| 438 | + | |
| 439 | + if (!$content) $content = $this->request($url, 'GET'); | |
| 440 | + | |
| 441 | + # At this point, the YADIS Discovery has failed, so we'll switch | |
| 442 | + # to openid2 HTML discovery, then fallback to openid 1.1 discovery. | |
| 443 | + $server = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href'); | |
| 444 | + $delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href'); | |
| 445 | + $this->version = 2; | |
| 446 | + | |
| 447 | + if (!$server) { | |
| 448 | + # The same with openid 1.1 | |
| 449 | + $server = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href'); | |
| 450 | + $delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href'); | |
| 451 | + $this->version = 1; | |
| 452 | + } | |
| 453 | + | |
| 454 | + if ($server) { | |
| 455 | + # We found an OpenID2 OP Endpoint | |
| 456 | + if ($delegate) { | |
| 457 | + # We have also found an OP-Local ID. | |
| 458 | + $this->identity = $delegate; | |
| 459 | + } | |
| 460 | + $this->server = $server; | |
| 461 | + return $server; | |
| 462 | + } | |
| 463 | + | |
| 464 | + throw new ErrorException('No servers found!'); | |
| 465 | + } | |
| 466 | + throw new ErrorException('Endless redirection!'); | |
| 467 | + } | |
| 468 | + | |
| 469 | + protected function sregParams() | |
| 470 | + { | |
| 471 | + $params = array(); | |
| 472 | + # We always use SREG 1.1, even if the server is advertising only support for 1.0. | |
| 473 | + # That's because it's fully backwards compatibile with 1.0, and some providers | |
| 474 | + # advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com | |
| 475 | + $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1'; | |
| 476 | + if ($this->required) { | |
| 477 | + $params['openid.sreg.required'] = array(); | |
| 478 | + foreach ($this->required as $required) { | |
| 479 | + if (!isset(self::$ax_to_sreg[$required])) continue; | |
| 480 | + $params['openid.sreg.required'][] = self::$ax_to_sreg[$required]; | |
| 481 | + } | |
| 482 | + $params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']); | |
| 483 | + } | |
| 484 | + | |
| 485 | + if ($this->optional) { | |
| 486 | + $params['openid.sreg.optional'] = array(); | |
| 487 | + foreach ($this->optional as $optional) { | |
| 488 | + if (!isset(self::$ax_to_sreg[$optional])) continue; | |
| 489 | + $params['openid.sreg.optional'][] = self::$ax_to_sreg[$optional]; | |
| 490 | + } | |
| 491 | + $params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']); | |
| 492 | + } | |
| 493 | + return $params; | |
| 494 | + } | |
| 495 | + | |
| 496 | + protected function axParams() | |
| 497 | + { | |
| 498 | + $params = array(); | |
| 499 | + if ($this->required || $this->optional) { | |
| 500 | + $params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0'; | |
| 501 | + $params['openid.ax.mode'] = 'fetch_request'; | |
| 502 | + $this->aliases = array(); | |
| 503 | + $counts = array(); | |
| 504 | + $required = array(); | |
| 505 | + $optional = array(); | |
| 506 | + foreach (array('required','optional') as $type) { | |
| 507 | + foreach ($this->$type as $alias => $field) { | |
| 508 | + if (is_int($alias)) $alias = strtr($field, '/', '_'); | |
| 509 | + $this->aliases[$alias] = 'http://axschema.org/' . $field; | |
| 510 | + if (empty($counts[$alias])) $counts[$alias] = 0; | |
| 511 | + $counts[$alias] += 1; | |
| 512 | + ${$type}[] = $alias; | |
| 513 | + } | |
| 514 | + } | |
| 515 | + foreach ($this->aliases as $alias => $ns) { | |
| 516 | + $params['openid.ax.type.' . $alias] = $ns; | |
| 517 | + } | |
| 518 | + foreach ($counts as $alias => $count) { | |
| 519 | + if ($count == 1) continue; | |
| 520 | + $params['openid.ax.count.' . $alias] = $count; | |
| 521 | + } | |
| 522 | + | |
| 523 | + # Don't send empty ax.requied and ax.if_available. | |
| 524 | + # Google and possibly other providers refuse to support ax when one of these is empty. | |
| 525 | + if($required) { | |
| 526 | + $params['openid.ax.required'] = implode(',', $required); | |
| 527 | + } | |
| 528 | + if($optional) { | |
| 529 | + $params['openid.ax.if_available'] = implode(',', $optional); | |
| 530 | + } | |
| 531 | + } | |
| 532 | + return $params; | |
| 533 | + } | |
| 534 | + | |
| 535 | + protected function authUrl_v1() | |
| 536 | + { | |
| 537 | + $returnUrl = $this->returnUrl; | |
| 538 | + # If we have an openid.delegate that is different from our claimed id, | |
| 539 | + # we need to somehow preserve the claimed id between requests. | |
| 540 | + # The simplest way is to just send it along with the return_to url. | |
| 541 | + if($this->identity != $this->claimed_id) { | |
| 542 | + $returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id; | |
| 543 | + } | |
| 544 | + | |
| 545 | + $params = array( | |
| 546 | + 'openid.return_to' => $returnUrl, | |
| 547 | + 'openid.mode' => 'checkid_setup', | |
| 548 | + 'openid.identity' => $this->identity, | |
| 549 | + 'openid.trust_root' => $this->trustRoot, | |
| 550 | + ) + $this->sregParams(); | |
| 551 | + | |
| 552 | + return $this->build_url(parse_url($this->server) | |
| 553 | + , array('query' => http_build_query($params, '', '&'))); | |
| 554 | + } | |
| 555 | + | |
| 556 | + protected function authUrl_v2($identifier_select) | |
| 557 | + { | |
| 558 | + $params = array( | |
| 559 | + 'openid.ns' => 'http://specs.openid.net/auth/2.0', | |
| 560 | + 'openid.mode' => 'checkid_setup', | |
| 561 | + 'openid.return_to' => $this->returnUrl, | |
| 562 | + 'openid.realm' => $this->trustRoot, | |
| 563 | + ); | |
| 564 | + if ($this->ax) { | |
| 565 | + $params += $this->axParams(); | |
| 566 | + } | |
| 567 | + if ($this->sreg) { | |
| 568 | + $params += $this->sregParams(); | |
| 569 | + } | |
| 570 | + if (!$this->ax && !$this->sreg) { | |
| 571 | + # If OP doesn't advertise either SREG, nor AX, let's send them both | |
| 572 | + # in worst case we don't get anything in return. | |
| 573 | + $params += $this->axParams() + $this->sregParams(); | |
| 574 | + } | |
| 575 | + | |
| 576 | + if ($identifier_select) { | |
| 577 | + $params['openid.identity'] = $params['openid.claimed_id'] | |
| 578 | + = 'http://specs.openid.net/auth/2.0/identifier_select'; | |
| 579 | + } else { | |
| 580 | + $params['openid.identity'] = $this->identity; | |
| 581 | + $params['openid.claimed_id'] = $this->claimed_id; | |
| 582 | + } | |
| 583 | + | |
| 584 | + return $this->build_url(parse_url($this->server) | |
| 585 | + , array('query' => http_build_query($params, '', '&'))); | |
| 586 | + } | |
| 587 | + | |
| 588 | + /** | |
| 589 | + * Returns authentication url. Usually, you want to redirect your user to it. | |
| 590 | + * @return String The authentication url. | |
| 591 | + * @param String $select_identifier Whether to request OP to select identity for an user in OpenID 2. Does not affect OpenID 1. | |
| 592 | + * @throws ErrorException | |
| 593 | + */ | |
| 594 | + function authUrl($identifier_select = null) | |
| 595 | + { | |
| 596 | + if (!$this->server) $this->discover($this->identity); | |
| 597 | + | |
| 598 | + if ($this->version == 2) { | |
| 599 | + if ($identifier_select === null) { | |
| 600 | + return $this->authUrl_v2($this->identifier_select); | |
| 601 | + } | |
| 602 | + return $this->authUrl_v2($identifier_select); | |
| 603 | + } | |
| 604 | + return $this->authUrl_v1(); | |
| 605 | + } | |
| 606 | + | |
| 607 | + /** | |
| 608 | + * Performs OpenID verification with the OP. | |
| 609 | + * @return Bool Whether the verification was successful. | |
| 610 | + * @throws ErrorException | |
| 611 | + */ | |
| 612 | + function validate() | |
| 613 | + { | |
| 614 | + $this->claimed_id = isset($this->data['openid_claimed_id'])?$this->data['openid_claimed_id']:$this->data['openid_identity']; | |
| 615 | + $params = array( | |
| 616 | + 'openid.assoc_handle' => $this->data['openid_assoc_handle'], | |
| 617 | + 'openid.signed' => $this->data['openid_signed'], | |
| 618 | + 'openid.sig' => $this->data['openid_sig'], | |
| 619 | + ); | |
| 620 | + | |
| 621 | + if (isset($this->data['openid_ns'])) { | |
| 622 | + # We're dealing with an OpenID 2.0 server, so let's set an ns | |
| 623 | + # Even though we should know location of the endpoint, | |
| 624 | + # we still need to verify it by discovery, so $server is not set here | |
| 625 | + $params['openid.ns'] = 'http://specs.openid.net/auth/2.0'; | |
| 626 | + } elseif (isset($this->data['openid_claimed_id']) | |
| 627 | + && $this->data['openid_claimed_id'] != $this->data['openid_identity'] | |
| 628 | + ) { | |
| 629 | + # If it's an OpenID 1 provider, and we've got claimed_id, | |
| 630 | + # we have to append it to the returnUrl, like authUrl_v1 does. | |
| 631 | + $this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?') | |
| 632 | + . 'openid.claimed_id=' . $this->claimed_id; | |
| 633 | + } | |
| 634 | + | |
| 635 | + if ($this->data['openid_return_to'] != $this->returnUrl) { | |
| 636 | + # The return_to url must match the url of current request. | |
| 637 | + # I'm assuing that noone will set the returnUrl to something that doesn't make sense. | |
| 638 | + return false; | |
| 639 | + } | |
| 640 | + | |
| 641 | + $server = $this->discover($this->claimed_id); | |
| 642 | + | |
| 643 | + foreach (explode(',', $this->data['openid_signed']) as $item) { | |
| 644 | + # Checking whether magic_quotes_gpc is turned on, because | |
| 645 | + # the function may fail if it is. For example, when fetching | |
| 646 | + # AX namePerson, it might containg an apostrophe, which will be escaped. | |
| 647 | + # In such case, validation would fail, since we'd send different data than OP | |
| 648 | + # wants to verify. stripslashes() should solve that problem, but we can't | |
| 649 | + # use it when magic_quotes is off. | |
| 650 | + $value = $this->data['openid_' . str_replace('.','_',$item)]; | |
| 651 | + $params['openid.' . $item] = get_magic_quotes_gpc() ? stripslashes($value) : $value; | |
| 652 | + | |
| 653 | + } | |
| 654 | + | |
| 655 | + $params['openid.mode'] = 'check_authentication'; | |
| 656 | + $response = $this->request($server, 'POST', $params); | |
| 657 | + return preg_match('/is_valid\s*:\s*true/i', $response); | |
| 658 | + } | |
| 659 | + | |
| 660 | + protected function getAxAttributes() | |
| 661 | + { | |
| 662 | + $alias = null; | |
| 663 | + if (isset($this->data['openid_ns_ax']) | |
| 664 | + && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0' | |
| 665 | + ) { # It's the most likely case, so we'll check it before | |
| 666 | + $alias = 'ax'; | |
| 667 | + } else { | |
| 668 | + # 'ax' prefix is either undefined, or points to another extension, | |
| 669 | + # so we search for another prefix | |
| 670 | + foreach ($this->data as $key => $val) { | |
| 671 | + if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_' | |
| 672 | + && $val == 'http://openid.net/srv/ax/1.0' | |
| 673 | + ) { | |
| 674 | + $alias = substr($key, strlen('openid_ns_')); | |
| 675 | + break; | |
| 676 | + } | |
| 677 | + } | |
| 678 | + } | |
| 679 | + if (!$alias) { | |
| 680 | + # An alias for AX schema has not been found, | |
| 681 | + # so there is no AX data in the OP's response | |
| 682 | + return array(); | |
| 683 | + } | |
| 684 | + | |
| 685 | + $attributes = array(); | |
| 686 | + foreach ($this->data as $key => $value) { | |
| 687 | + $keyMatch = 'openid_' . $alias . '_value_'; | |
| 688 | + if (substr($key, 0, strlen($keyMatch)) != $keyMatch) { | |
| 689 | + continue; | |
| 690 | + } | |
| 691 | + $key = substr($key, strlen($keyMatch)); | |
| 692 | + if (!isset($this->data['openid_' . $alias . '_type_' . $key])) { | |
| 693 | + # OP is breaking the spec by returning a field without | |
| 694 | + # associated ns. This shouldn't happen, but it's better | |
| 695 | + # to check, than cause an E_NOTICE. | |
| 696 | + continue; | |
| 697 | + } | |
| 698 | + $key = substr($this->data['openid_' . $alias . '_type_' . $key], | |
| 699 | + strlen('http://axschema.org/')); | |
| 700 | + $attributes[$key] = $value; | |
| 701 | + } | |
| 702 | + return $attributes; | |
| 703 | + } | |
| 704 | + | |
| 705 | + protected function getSregAttributes() | |
| 706 | + { | |
| 707 | + $attributes = array(); | |
| 708 | + $sreg_to_ax = array_flip(self::$ax_to_sreg); | |
| 709 | + foreach ($this->data as $key => $value) { | |
| 710 | + $keyMatch = 'openid_sreg_'; | |
| 711 | + if (substr($key, 0, strlen($keyMatch)) != $keyMatch) { | |
| 712 | + continue; | |
| 713 | + } | |
| 714 | + $key = substr($key, strlen($keyMatch)); | |
| 715 | + if (!isset($sreg_to_ax[$key])) { | |
| 716 | + # The field name isn't part of the SREG spec, so we ignore it. | |
| 717 | + continue; | |
| 718 | + } | |
| 719 | + $attributes[$sreg_to_ax[$key]] = $value; | |
| 720 | + } | |
| 721 | + return $attributes; | |
| 722 | + } | |
| 723 | + | |
| 724 | + /** | |
| 725 | + * Gets AX/SREG attributes provided by OP. should be used only after successful validaton. | |
| 726 | + * Note that it does not guarantee that any of the required/optional parameters will be present, | |
| 727 | + * or that there will be no other attributes besides those specified. | |
| 728 | + * In other words. OP may provide whatever information it wants to. | |
| 729 | + * * SREG names will be mapped to AX names. | |
| 730 | + * * @return Array Array of attributes with keys being the AX schema names, e.g. 'contact/email' | |
| 731 | + * @see http://www.axschema.org/types/ | |
| 732 | + */ | |
| 733 | + function getAttributes() | |
| 734 | + { | |
| 735 | + if (isset($this->data['openid_ns']) | |
| 736 | + && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0' | |
| 737 | + ) { # OpenID 2.0 | |
| 738 | + # We search for both AX and SREG attributes, with AX taking precedence. | |
| 739 | + return $this->getAxAttributes() + $this->getSregAttributes(); | |
| 740 | + } | |
| 741 | + return $this->getSregAttributes(); | |
| 742 | + } | |
| 743 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,194 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * This example shows several things: | |
| 4 | + * - How a setup interface should look like. | |
| 5 | + * - How to use a mysql table for authentication | |
| 6 | + * - How to store associations in mysql table, instead of php sessions. | |
| 7 | + * - How to store realm authorizations. | |
| 8 | + * - How to send AX/SREG parameters. | |
| 9 | + * For the example to work, you need to create the necessary tables: | |
| 10 | +CREATE TABLE Users ( | |
| 11 | + id INT NOT NULL auto_increment PRIMARY KEY, | |
| 12 | + login VARCHAR(32) NOT NULL, | |
| 13 | + password CHAR(40) NOT NULL, | |
| 14 | + firstName VARCHAR(32) NOT NULL, | |
| 15 | + lastName VARCHAR(32) NOT NULL | |
| 16 | +); | |
| 17 | + | |
| 18 | +CREATE TABLE AllowedSites ( | |
| 19 | + user INT NOT NULL, | |
| 20 | + realm TEXT NOT NULL, | |
| 21 | + attributes TEXT NOT NULL, | |
| 22 | + INDEX(user) | |
| 23 | +); | |
| 24 | + | |
| 25 | +CREATE TABLE Associations ( | |
| 26 | + id INT NOT NULL PRIMARY KEY, | |
| 27 | + data TEXT NOT NULL | |
| 28 | +); | |
| 29 | + * | |
| 30 | + * This is only an example. Don't use it in your code as-is. | |
| 31 | + * It has several security flaws, which you shouldn't copy (like storing plaintext login and password in forms). | |
| 32 | + * | |
| 33 | + * This setup could be very easily flooded with many associations, | |
| 34 | + * since non-private ones aren't automatically deleted. | |
| 35 | + * You could prevent this by storing a date of association and removing old ones, | |
| 36 | + * or by setting $this->dh = false; | |
| 37 | + * However, the latter one would disable stateful mode, unless connecting via HTTPS. | |
| 38 | + */ | |
| 39 | +require 'provider.php'; | |
| 40 | + | |
| 41 | +mysql_connect(); | |
| 42 | +mysql_select_db('test'); | |
| 43 | + | |
| 44 | +function getUserData($handle=null) | |
| 45 | +{ | |
| 46 | + if(isset($_POST['login'],$_POST['password'])) { | |
| 47 | + $login = mysql_real_escape_string($_POST['login']); | |
| 48 | + $password = sha1($_POST['password']); | |
| 49 | + $q = mysql_query("SELECT * FROM Users WHERE login = '$login' AND password = '$password'"); | |
| 50 | + if($data = mysql_fetch_assoc($q)) { | |
| 51 | + return $data; | |
| 52 | + } | |
| 53 | + if($handle) { | |
| 54 | + echo 'Wrong login/password.'; | |
| 55 | + } | |
| 56 | + } | |
| 57 | + if($handle) { | |
| 58 | + ?> | |
| 59 | + <form action="" method="post"> | |
| 60 | + <input type="hidden" name="openid.assoc_handle" value="<?php echo $handle?>"> | |
| 61 | + Login: <input type="text" name="login"><br> | |
| 62 | + Password: <input type="password" name="password"><br> | |
| 63 | + <button>Submit</button> | |
| 64 | + </form> | |
| 65 | + <?php | |
| 66 | + die(); | |
| 67 | + } | |
| 68 | +} | |
| 69 | + | |
| 70 | +class MysqlProvider extends LightOpenIDProvider | |
| 71 | +{ | |
| 72 | + private $attrMap = array( | |
| 73 | + 'namePerson/first' => 'First name', | |
| 74 | + 'namePerson/last' => 'Last name', | |
| 75 | + 'namePerson/friendly' => 'Nickname (login)' | |
| 76 | + ); | |
| 77 | + | |
| 78 | + private $attrFieldMap = array( | |
| 79 | + 'namePerson/first' => 'firstName', | |
| 80 | + 'namePerson/last' => 'lastName', | |
| 81 | + 'namePerson/friendly' => 'login' | |
| 82 | + ); | |
| 83 | + | |
| 84 | + function setup($identity, $realm, $assoc_handle, $attributes) | |
| 85 | + { | |
| 86 | + $data = getUserData($assoc_handle); | |
| 87 | + echo '<form action="" method="post">' | |
| 88 | + . '<input type="hidden" name="openid.assoc_handle" value="' . $assoc_handle . '">' | |
| 89 | + . '<input type="hidden" name="login" value="' . $_POST['login'] .'">' | |
| 90 | + . '<input type="hidden" name="password" value="' . $_POST['password'] .'">' | |
| 91 | + . "<b>$realm</b> wishes to authenticate you."; | |
| 92 | + if($attributes['required'] || $attributes['optional']) { | |
| 93 | + echo " It also requests following information (required fields marked with *):" | |
| 94 | + . '<ul>'; | |
| 95 | + | |
| 96 | + foreach($attributes['required'] as $attr) { | |
| 97 | + if(isset($this->attrMap[$attr])) { | |
| 98 | + echo '<li>' | |
| 99 | + . '<input type="checkbox" name="attributes[' . $attr . ']"> ' | |
| 100 | + . $this->attrMap[$attr] . '(*)</li>'; | |
| 101 | + } | |
| 102 | + } | |
| 103 | + | |
| 104 | + foreach($attributes['optional'] as $attr) { | |
| 105 | + if(isset($this->attrMap[$attr])) { | |
| 106 | + echo '<li>' | |
| 107 | + . '<input type="checkbox" name="attributes[' . $attr . ']"> ' | |
| 108 | + . $this->attrMap[$attr] . '</li>'; | |
| 109 | + } | |
| 110 | + } | |
| 111 | + echo '</ul>'; | |
| 112 | + } | |
| 113 | + echo '<br>' | |
| 114 | + . '<button name="once">Allow once</button> ' | |
| 115 | + . '<button name="always">Always allow</button> ' | |
| 116 | + . '<button name="cancel">cancel</button> ' | |
| 117 | + . '</form>'; | |
| 118 | + } | |
| 119 | + | |
| 120 | + function checkid($realm, &$attributes) | |
| 121 | + { | |
| 122 | + if(isset($_POST['cancel'])) { | |
| 123 | + $this->cancel(); | |
| 124 | + } | |
| 125 | + | |
| 126 | + $data = getUserData(); | |
| 127 | + if(!$data) { | |
| 128 | + return false; | |
| 129 | + } | |
| 130 | + $realm = mysql_real_escape_string($realm); | |
| 131 | + $q = mysql_query("SELECT attributes FROM AllowedSites WHERE user = '{$data['id']}' AND realm = '$realm'"); | |
| 132 | + | |
| 133 | + $attrs = array(); | |
| 134 | + if($attrs = mysql_fetch_row($q)) { | |
| 135 | + $attrs = explode(',', $attributes[0]); | |
| 136 | + } elseif(isset($_POST['attributes'])) { | |
| 137 | + $attrs = array_keys($_POST['attributes']); | |
| 138 | + } elseif(!isset($_POST['once']) && !isset($_POST['always'])) { | |
| 139 | + return false; | |
| 140 | + } | |
| 141 | + | |
| 142 | + $attributes = array(); | |
| 143 | + foreach($attrs as $attr) { | |
| 144 | + if(isset($this->attrFieldMap[$attr])) { | |
| 145 | + $attributes[$attr] = $data[$this->attrFieldMap[$attr]]; | |
| 146 | + } | |
| 147 | + } | |
| 148 | + | |
| 149 | + if(isset($_POST['always'])) { | |
| 150 | + $attrs = mysql_real_escape_string(implode(',', array_keys($attributes))); | |
| 151 | + mysql_query("REPLACE INTO AllowedSites VALUES('{$data['id']}', '$realm', '$attrs')"); | |
| 152 | + } | |
| 153 | + | |
| 154 | + return $this->serverLocation . '?' . $data['login']; | |
| 155 | + } | |
| 156 | + | |
| 157 | + function assoc_handle() | |
| 158 | + { | |
| 159 | + # We generate an integer assoc handle, because it's just faster to look up an integer later. | |
| 160 | + $q = mysql_query("SELECT MAX(id) FROM Associations"); | |
| 161 | + $result = mysql_fetch_row($q); | |
| 162 | + return $q[0]+1; | |
| 163 | + } | |
| 164 | + | |
| 165 | + function setAssoc($handle, $data) | |
| 166 | + { | |
| 167 | + $data = mysql_real_escape_string(serialize($data)); | |
| 168 | + mysql_query("REPLACE INTO Associations VALUES('$handle', '$data')"); | |
| 169 | + } | |
| 170 | + | |
| 171 | + function getAssoc($handle) | |
| 172 | + { | |
| 173 | + if(!is_numeric($handle)) { | |
| 174 | + return false; | |
| 175 | + } | |
| 176 | + $q = mysql_query("SELECT data FROM Associations WHERE id = '$handle'"); | |
| 177 | + $data = mysql_fetch_row($q); | |
| 178 | + if(!$data) { | |
| 179 | + return false; | |
| 180 | + } | |
| 181 | + return unserialize($data[0]); | |
| 182 | + } | |
| 183 | + | |
| 184 | + function delAssoc($handle) | |
| 185 | + { | |
| 186 | + if(!is_numeric($handle)) { | |
| 187 | + return false; | |
| 188 | + } | |
| 189 | + mysql_query("DELETE FROM Associations WHERE id = '$handle'"); | |
| 190 | + } | |
| 191 | + | |
| 192 | +} | |
| 193 | +$op = new MysqlProvider; | |
| 194 | +$op->server(); | ... | ... |
| ... | ... | @@ -0,0 +1,53 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * This example shows how to create a basic provider usin HTTP Authentication. | |
| 4 | + * This is only an example. You shouldn't use it as-is in your code. | |
| 5 | + */ | |
| 6 | +require 'provider.php'; | |
| 7 | + | |
| 8 | +class BasicProvider extends LightOpenIDProvider | |
| 9 | +{ | |
| 10 | + public $select_id = true; | |
| 11 | + public $login = ''; | |
| 12 | + public $password = ''; | |
| 13 | + | |
| 14 | + function __construct() | |
| 15 | + { | |
| 16 | + parent::__construct(); | |
| 17 | + | |
| 18 | + # If we use select_id, we must disable it for identity pages, | |
| 19 | + # so that an RP can discover it and get proper data (i.e. without select_id) | |
| 20 | + if(isset($_GET['id'])) { | |
| 21 | + $this->select_id = false; | |
| 22 | + } | |
| 23 | + } | |
| 24 | + | |
| 25 | + function setup($identity, $realm, $assoc_handle, $attributes) | |
| 26 | + { | |
| 27 | + header('WWW-Authenticate: Basic realm="' . $this->data['openid_realm'] . '"'); | |
| 28 | + header('HTTP/1.0 401 Unauthorized'); | |
| 29 | + } | |
| 30 | + | |
| 31 | + function checkid($realm, &$attributes) | |
| 32 | + { | |
| 33 | + if(!isset($_SERVER['PHP_AUTH_USER'])) { | |
| 34 | + return false; | |
| 35 | + } | |
| 36 | + | |
| 37 | + if ($_SERVER['PHP_AUTH_USER'] == $this->login | |
| 38 | + && $_SERVER['PHP_AUTH_PW'] == $this->password | |
| 39 | + ) { | |
| 40 | + # Returning identity | |
| 41 | + # It can be any url that leads here, or to any other place that hosts | |
| 42 | + # an XRDS document pointing here. | |
| 43 | + return $this->serverLocation . '?id=' . $this->login; | |
| 44 | + } | |
| 45 | + | |
| 46 | + return false; | |
| 47 | + } | |
| 48 | + | |
| 49 | +} | |
| 50 | +$op = new BasicProvider; | |
| 51 | +$op->login = 'test'; | |
| 52 | +$op->password = 'test'; | |
| 53 | +$op->server(); | ... | ... |
| ... | ... | @@ -0,0 +1,833 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * Using this class, you can easily set up an OpenID Provider. | |
| 4 | + * It's independent of LightOpenID class. | |
| 5 | + * It requires either GMP or BCMath for session encryption, | |
| 6 | + * but will work without them (although either via SSL, or in stateless mode only). | |
| 7 | + * Also, it requires PHP >= 5.1.2 | |
| 8 | + * | |
| 9 | + * This is an alpha version, using it in production code is not recommended, | |
| 10 | + * until you are *sure* that it works and is secure. | |
| 11 | + * | |
| 12 | + * Please send me messages about your testing results | |
| 13 | + * (even if successful, so I know that it has been tested). | |
| 14 | + * Also, if you think there's a way to make it easier to use, tell me -- it's an alpha for a reason. | |
| 15 | + * Same thing applies to bugs in code, suggestions, | |
| 16 | + * and everything else you'd like to say about the library. | |
| 17 | + * | |
| 18 | + * There's no usage documentation here, see the examples. | |
| 19 | + * | |
| 20 | + * @author Mewp | |
| 21 | + * @copyright Copyright (c) 2010, Mewp | |
| 22 | + * @license http://www.opensource.org/licenses/mit-license.php MIT | |
| 23 | + */ | |
| 24 | +ini_set('error_log','log'); | |
| 25 | +abstract class LightOpenIDProvider | |
| 26 | +{ | |
| 27 | + # URL-s to XRDS and server location. | |
| 28 | + public $xrdsLocation, $serverLocation; | |
| 29 | + | |
| 30 | + # Should we operate in server, or signon mode? | |
| 31 | + public $select_id = false; | |
| 32 | + | |
| 33 | + # Lifetime of an association. | |
| 34 | + protected $assoc_lifetime = 600; | |
| 35 | + | |
| 36 | + # Variables below are either set automatically, or are constant. | |
| 37 | + # ----- | |
| 38 | + # Can we support DH? | |
| 39 | + protected $dh = true; | |
| 40 | + protected $ns = 'http://specs.openid.net/auth/2.0'; | |
| 41 | + protected $data, $assoc; | |
| 42 | + | |
| 43 | + # Default DH parameters as defined in the specification. | |
| 44 | + protected $default_modulus; | |
| 45 | + protected $default_gen = 'Ag=='; | |
| 46 | + | |
| 47 | + # AX <-> SREG transform | |
| 48 | + protected $ax_to_sreg = array( | |
| 49 | + 'namePerson/friendly' => 'nickname', | |
| 50 | + 'contact/email' => 'email', | |
| 51 | + 'namePerson' => 'fullname', | |
| 52 | + 'birthDate' => 'dob', | |
| 53 | + 'person/gender' => 'gender', | |
| 54 | + 'contact/postalCode/home' => 'postcode', | |
| 55 | + 'contact/country/home' => 'country', | |
| 56 | + 'pref/language' => 'language', | |
| 57 | + 'pref/timezone' => 'timezone', | |
| 58 | + ); | |
| 59 | + | |
| 60 | + # Math | |
| 61 | + private $add, $mul, $pow, $mod, $div, $powmod; | |
| 62 | + # ----- | |
| 63 | + | |
| 64 | + # ------------------------------------------------------------------------ # | |
| 65 | + # Functions you probably want to implement when extending the class. | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * Checks whether an user is authenticated. | |
| 69 | + * The function should determine what fields it wants to send to the RP, | |
| 70 | + * and put them in the $attributes array. | |
| 71 | + * @param Array $attributes | |
| 72 | + * @param String $realm Realm used for authentication. | |
| 73 | + * @return String OP-local identifier of an authenticated user, or an empty value. | |
| 74 | + */ | |
| 75 | + abstract function checkid($realm, &$attributes); | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Displays an user interface for inputting user's login and password. | |
| 79 | + * Attributes are always AX field namespaces, with stripped host part. | |
| 80 | + * For example, the $attributes array may be: | |
| 81 | + * array( 'required' => array('namePerson/friendly', 'contact/email'), | |
| 82 | + * 'optional' => array('pref/timezone', 'pref/language') | |
| 83 | + * @param String $identity Discovered identity string. May be used to extract login, unless using $this->select_id | |
| 84 | + * @param String $realm Realm used for authentication. | |
| 85 | + * @param String Association handle. must be sent as openid.assoc_handle in $_GET or $_POST in subsequent requests. | |
| 86 | + * @param Array User attributes requested by the RP. | |
| 87 | + */ | |
| 88 | + abstract function setup($identity, $realm, $assoc_handle, $attributes); | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Stores an association. | |
| 92 | + * If you want to use php sessions in your provider code, you have to replace it. | |
| 93 | + * @param String $handle Association handle -- should be used as a key. | |
| 94 | + * @param Array $assoc Association data. | |
| 95 | + */ | |
| 96 | + protected function setAssoc($handle, $assoc) | |
| 97 | + { | |
| 98 | + if(session_id()) session_destroy(); | |
| 99 | + session_id($assoc['handle']); | |
| 100 | + session_start(); | |
| 101 | + $_SESSION['assoc'] = $assoc; | |
| 102 | + session_commit(); | |
| 103 | + session_id(''); | |
| 104 | + } | |
| 105 | + | |
| 106 | + /** | |
| 107 | + * Retreives association data. | |
| 108 | + * If you want to use php sessions in your provider code, you have to replace it. | |
| 109 | + * @param String $handle Association handle. | |
| 110 | + * @return Array Association data. | |
| 111 | + */ | |
| 112 | + protected function getAssoc($handle) | |
| 113 | + { | |
| 114 | + if(session_id()) session_destroy(); | |
| 115 | + session_id($handle); | |
| 116 | + session_start(); | |
| 117 | + if(empty($_SESSION['assoc'])) { | |
| 118 | + return null; | |
| 119 | + } | |
| 120 | + return $_SESSION['assoc']; | |
| 121 | + session_commit(); | |
| 122 | + session_id(''); | |
| 123 | + } | |
| 124 | + | |
| 125 | + /** | |
| 126 | + * Deletes an association. | |
| 127 | + * If you want to use php sessions in your provider code, you have to replace it. | |
| 128 | + * @param String $handle Association handle. | |
| 129 | + */ | |
| 130 | + protected function delAssoc($handle) | |
| 131 | + { | |
| 132 | + if(session_id()) session_destroy(); | |
| 133 | + session_id($handle); | |
| 134 | + session_start(); | |
| 135 | + session_destroy(); | |
| 136 | + session_id(''); | |
| 137 | + } | |
| 138 | + | |
| 139 | + # ------------------------------------------------------------------------ # | |
| 140 | + # Functions that you might want to implement. | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * Redirects the user to an url. | |
| 144 | + * @param String $location The url that the user will be redirected to. | |
| 145 | + */ | |
| 146 | + protected function redirect($location) | |
| 147 | + { | |
| 148 | + header('Location: ' . $location); | |
| 149 | + die(); | |
| 150 | + } | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * Generates a new association handle. | |
| 154 | + * @return string | |
| 155 | + */ | |
| 156 | + protected function assoc_handle() | |
| 157 | + { | |
| 158 | + return sha1(microtime()); | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * Generates a random shared secret. | |
| 163 | + * @return string | |
| 164 | + */ | |
| 165 | + protected function shared_secret($hash) | |
| 166 | + { | |
| 167 | + $length = 20; | |
| 168 | + if($hash == 'sha256') { | |
| 169 | + $length = 256; | |
| 170 | + } | |
| 171 | + | |
| 172 | + $secret = ''; | |
| 173 | + for($i = 0; $i < $length; $i++) { | |
| 174 | + $secret .= mt_rand(0,255); | |
| 175 | + } | |
| 176 | + | |
| 177 | + return $secret; | |
| 178 | + } | |
| 179 | + | |
| 180 | + /** | |
| 181 | + * Generates a private key. | |
| 182 | + * @param int $length Length of the key. | |
| 183 | + */ | |
| 184 | + protected function keygen($length) | |
| 185 | + { | |
| 186 | + $key = ''; | |
| 187 | + for($i = 1; $i < $length; $i++) { | |
| 188 | + $key .= mt_rand(0,9); | |
| 189 | + } | |
| 190 | + $key .= mt_rand(1,9); | |
| 191 | + | |
| 192 | + return $key; | |
| 193 | + } | |
| 194 | + | |
| 195 | + # ------------------------------------------------------------------------ # | |
| 196 | + # Functions that you probably shouldn't touch. | |
| 197 | + | |
| 198 | + function __construct() | |
| 199 | + { | |
| 200 | + $this->default_modulus = | |
| 201 | + 'ANz5OguIOXLsDhmYmsWizjEOHTdxfo2Vcbt2I3MYZuYe91ouJ4mLBX+YkcLiemOcPy' | |
| 202 | + . 'm2CBRYHNOyyjmG0mg3BVd9RcLn5S3IHHoXGHblzqdLFEi/368Ygo79JRnxTkXjgmY0' | |
| 203 | + . 'rxlJ5bU1zIKaSDuKdiI+XUkKJX8Fvf8W8vsixYOr'; | |
| 204 | + | |
| 205 | + $location = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' | |
| 206 | + . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; | |
| 207 | + $location = preg_replace('/\?.*/','',$location); | |
| 208 | + $this->serverLocation = $location; | |
| 209 | + $location .= (strpos($location, '?') ? '&' : '?') . 'xrds'; | |
| 210 | + $this->xrdsLocation = $location; | |
| 211 | + | |
| 212 | + $this->data = $_GET + $_POST; | |
| 213 | + | |
| 214 | + # We choose GMP if avaiable, and bcmath otherwise | |
| 215 | + if(function_exists('gmp_add')) { | |
| 216 | + $this->add = 'gmp_add'; | |
| 217 | + $this->mul = 'gmp_mul'; | |
| 218 | + $this->pow = 'gmp_pow'; | |
| 219 | + $this->mod = 'gmp_mod'; | |
| 220 | + $this->div = 'gmp_div'; | |
| 221 | + $this->powmod = 'gmp_powm'; | |
| 222 | + } elseif(function_exists('bcadd')) { | |
| 223 | + $this->add = 'bcadd'; | |
| 224 | + $this->mul = 'bcmul'; | |
| 225 | + $this->pow = 'bcpow'; | |
| 226 | + $this->mod = 'bcmod'; | |
| 227 | + $this->div = 'bcdiv'; | |
| 228 | + $this->powmod = 'bcpowmod'; | |
| 229 | + } else { | |
| 230 | + # If neither are avaiable, we can't use DH | |
| 231 | + $this->dh = false; | |
| 232 | + } | |
| 233 | + | |
| 234 | + # However, we do require the hash functions. | |
| 235 | + # They should be built-in anyway. | |
| 236 | + if(!function_exists('hash_algos')) { | |
| 237 | + $this->dh = false; | |
| 238 | + } | |
| 239 | + } | |
| 240 | + | |
| 241 | + /** | |
| 242 | + * Displays an XRDS document, or redirects to it. | |
| 243 | + * By default, it detects whether it should display or redirect automatically. | |
| 244 | + * @param bool|null $force When true, always display the document, when false always redirect. | |
| 245 | + */ | |
| 246 | + function xrds($force=null) | |
| 247 | + { | |
| 248 | + if($force) { | |
| 249 | + echo $this->xrdsContent(); | |
| 250 | + die(); | |
| 251 | + } elseif($force === false) { | |
| 252 | + header('X-XRDS-Location: '. $this->xrdsLocation); | |
| 253 | + return; | |
| 254 | + } | |
| 255 | + | |
| 256 | + if (isset($_GET['xrds']) | |
| 257 | + || (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'application/xrds+xml') !== false) | |
| 258 | + ) { | |
| 259 | + header('Content-Type: application/xrds+xml'); | |
| 260 | + echo $this->xrdsContent(); | |
| 261 | + die(); | |
| 262 | + } | |
| 263 | + | |
| 264 | + header('X-XRDS-Location: ' . $this->xrdsLocation); | |
| 265 | + } | |
| 266 | + | |
| 267 | + /** | |
| 268 | + * Returns the content of the XRDS document | |
| 269 | + * @return String The XRDS document. | |
| 270 | + */ | |
| 271 | + protected function xrdsContent() | |
| 272 | + { | |
| 273 | + $lines = array( | |
| 274 | + '<?xml version="1.0" encoding="UTF-8"?>', | |
| 275 | + '<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">', | |
| 276 | + '<XRD>', | |
| 277 | + ' <Service>', | |
| 278 | + ' <Type>' . $this->ns . '/' . ($this->select_id ? 'server' : 'signon') .'</Type>', | |
| 279 | + ' <URI>' . $this->serverLocation . '</URI>', | |
| 280 | + ' </Service>', | |
| 281 | + '</XRD>', | |
| 282 | + '</xrds:XRDS>' | |
| 283 | + ); | |
| 284 | + return implode("\n", $lines); | |
| 285 | + } | |
| 286 | + | |
| 287 | + /** | |
| 288 | + * Does everything that a provider has to -- in one function. | |
| 289 | + */ | |
| 290 | + function server() | |
| 291 | + { | |
| 292 | + if(isset($this->data['openid_assoc_handle'])) { | |
| 293 | + $this->assoc = $this->getAssoc($this->data['openid_assoc_handle']); | |
| 294 | + if(isset($this->assoc['data'])) { | |
| 295 | + # We have additional data stored for setup. | |
| 296 | + $this->data += $this->assoc['data']; | |
| 297 | + unset($this->assoc['data']); | |
| 298 | + } | |
| 299 | + } | |
| 300 | + | |
| 301 | + if (isset($this->data['openid_ns']) | |
| 302 | + && $this->data['openid_ns'] == $this->ns | |
| 303 | + ) { | |
| 304 | + if(!isset($this->data['openid_mode'])) $this->errorResponse(); | |
| 305 | + | |
| 306 | + switch($this->data['openid_mode']) | |
| 307 | + { | |
| 308 | + case 'checkid_immediate': | |
| 309 | + case 'checkid_setup': | |
| 310 | + $this->checkRealm(); | |
| 311 | + # We support AX xor SREG. | |
| 312 | + $attributes = $this->ax(); | |
| 313 | + if(!$attributes) { | |
| 314 | + $attributes = $this->sreg(); | |
| 315 | + } | |
| 316 | + | |
| 317 | + # Even if some user is authenticated, we need to know if it's | |
| 318 | + # the same one that want's to authenticate. | |
| 319 | + # Of course, if we use select_id, we accept any user. | |
| 320 | + if (($identity = $this->checkid($this->data['openid_realm'], $attrValues)) | |
| 321 | + && ($this->select_id || $identity == $this->data['openid_identity']) | |
| 322 | + ) { | |
| 323 | + $this->positiveResponse($identity, $attrValues); | |
| 324 | + } elseif($this->data['openid_mode'] == 'checkid_immediate') { | |
| 325 | + $this->redirect($this->response(array('openid.mode' => 'setup_needed'))); | |
| 326 | + } else { | |
| 327 | + if(!$this->assoc) { | |
| 328 | + $this->generateAssociation(); | |
| 329 | + $this->assoc['private'] = true; | |
| 330 | + } | |
| 331 | + $this->assoc['data'] = $this->data; | |
| 332 | + $this->setAssoc($this->assoc['handle'], $this->assoc); | |
| 333 | + $this->setup($this->data['openid_identity'], | |
| 334 | + $this->data['openid_realm'], | |
| 335 | + $this->assoc['handle'], | |
| 336 | + $attributes); | |
| 337 | + } | |
| 338 | + break; | |
| 339 | + case 'associate': | |
| 340 | + $this->associate(); | |
| 341 | + break; | |
| 342 | + case 'check_authentication': | |
| 343 | + $this->checkRealm(); | |
| 344 | + if($this->verify()) { | |
| 345 | + echo "ns:$this->ns\nis_valid:true"; | |
| 346 | + if(strpos($this->data['openid_signed'],'invalidate_handle') !== false) { | |
| 347 | + echo "\ninvalidate_handle:" . $this->data['openid_invalidate_handle']; | |
| 348 | + } | |
| 349 | + } else { | |
| 350 | + echo "ns:$this->ns\nis_valid:false"; | |
| 351 | + } | |
| 352 | + die(); | |
| 353 | + break; | |
| 354 | + default: | |
| 355 | + $this->errorResponse(); | |
| 356 | + } | |
| 357 | + } else { | |
| 358 | + $this->xrds(); | |
| 359 | + } | |
| 360 | + } | |
| 361 | + | |
| 362 | + protected function checkRealm() | |
| 363 | + { | |
| 364 | + if (!isset($this->data['openid_return_to'], $this->data['openid_realm'])) { | |
| 365 | + $this->errorResponse(); | |
| 366 | + } | |
| 367 | + | |
| 368 | + $realm = str_replace('\*', '[^/]', preg_quote($this->data['openid_realm'])); | |
| 369 | + if(!preg_match("#^$realm#", $this->data['openid_return_to'])) { | |
| 370 | + $this->errorResponse(); | |
| 371 | + } | |
| 372 | + } | |
| 373 | + | |
| 374 | + protected function ax() | |
| 375 | + { | |
| 376 | + # Namespace prefix that the fields must have. | |
| 377 | + $ns = 'http://axschema.org/'; | |
| 378 | + | |
| 379 | + # First, we must find out what alias is used for AX. | |
| 380 | + # Let's check the most likely one | |
| 381 | + $alias = null; | |
| 382 | + if (isset($this->data['openid_ns_ax']) | |
| 383 | + && $this->data['openid_ns_ax'] == 'http://openid.net/srv/ax/1.0' | |
| 384 | + ) { | |
| 385 | + $alias = 'ax'; | |
| 386 | + } else { | |
| 387 | + foreach($this->data as $name => $value) { | |
| 388 | + if ($value == 'http://openid.net/srv/ax/1.0' | |
| 389 | + && preg_match('/openid_ns_(.+)/', $name, $m) | |
| 390 | + ) { | |
| 391 | + $alias = $m[1]; | |
| 392 | + break; | |
| 393 | + } | |
| 394 | + } | |
| 395 | + } | |
| 396 | + | |
| 397 | + if(!$alias) { | |
| 398 | + return null; | |
| 399 | + } | |
| 400 | + | |
| 401 | + $fields = array(); | |
| 402 | + # Now, we must search again, this time for field aliases | |
| 403 | + foreach($this->data as $name => $value) { | |
| 404 | + if (strpos($name, 'openid_' . $alias . '_type') === false | |
| 405 | + || strpos($value, $ns) === false) { | |
| 406 | + continue; | |
| 407 | + } | |
| 408 | + | |
| 409 | + $name = substr($name, strlen('openid_' . $alias . '_type_')); | |
| 410 | + $value = substr($value, strlen($ns)); | |
| 411 | + | |
| 412 | + $fields[$name] = $value; | |
| 413 | + } | |
| 414 | + | |
| 415 | + # Then, we find out what fields are required and optional | |
| 416 | + $required = array(); | |
| 417 | + $if_available = array(); | |
| 418 | + foreach(array('required','if_available') as $type) { | |
| 419 | + if(empty($this->data["openid_{$alias}_{$type}"])) { | |
| 420 | + continue; | |
| 421 | + } | |
| 422 | + $attributes = explode(',', $this->data["openid_{$alias}_{$type}"]); | |
| 423 | + foreach($attributes as $attr) { | |
| 424 | + if(empty($fields[$attr])) { | |
| 425 | + # There is an undefined field here, so we ignore it. | |
| 426 | + continue; | |
| 427 | + } | |
| 428 | + | |
| 429 | + ${$type}[] = $fields[$attr]; | |
| 430 | + } | |
| 431 | + } | |
| 432 | + | |
| 433 | + $this->data['ax'] = true; | |
| 434 | + return array('required' => $required, 'optional' => $if_available); | |
| 435 | + } | |
| 436 | + | |
| 437 | + protected function sreg() | |
| 438 | + { | |
| 439 | + $sreg_to_ax = array_flip($this->ax_to_sreg); | |
| 440 | + | |
| 441 | + $attributes = array('required' => array(), 'optional' => array()); | |
| 442 | + | |
| 443 | + if (empty($this->data['openid_sreg_required']) | |
| 444 | + && empty($this->data['openid_sreg_optional']) | |
| 445 | + ) { | |
| 446 | + return $attributes; | |
| 447 | + } | |
| 448 | + | |
| 449 | + foreach(array('required', 'optional') as $type) { | |
| 450 | + foreach(explode(',',$this->data['openid_sreg_' . $type]) as $attr) { | |
| 451 | + if(empty($sreg_to_ax[$attr])) { | |
| 452 | + # Undefined attribute in SREG request. | |
| 453 | + # Shouldn't happen, but we check anyway. | |
| 454 | + continue; | |
| 455 | + } | |
| 456 | + | |
| 457 | + $attributes[$type][] = $sreg_to_ax[$attr]; | |
| 458 | + } | |
| 459 | + } | |
| 460 | + | |
| 461 | + return $attributes; | |
| 462 | + } | |
| 463 | + | |
| 464 | + /** | |
| 465 | + * Aids an RP in assertion verification. | |
| 466 | + * @return bool Information whether the verification suceeded. | |
| 467 | + */ | |
| 468 | + protected function verify() | |
| 469 | + { | |
| 470 | + # Firstly, we need to make sure that there's an association. | |
| 471 | + # Otherwise the verification will fail, | |
| 472 | + # because we've signed assoc_handle in the assertion | |
| 473 | + if(empty($this->assoc)) { | |
| 474 | + return false; | |
| 475 | + } | |
| 476 | + | |
| 477 | + # Next, we check that it's a private association, | |
| 478 | + # i.e. one made without RP input. | |
| 479 | + # Otherwise, the RP shouldn't ask us to verify. | |
| 480 | + if(empty($this->assoc['private'])) { | |
| 481 | + return false; | |
| 482 | + } | |
| 483 | + | |
| 484 | + # Now we have to check if the nonce is correct, to prevent replay attacks. | |
| 485 | + if($this->data['openid_response_nonce'] != $this->assoc['nonce']) { | |
| 486 | + return false; | |
| 487 | + } | |
| 488 | + | |
| 489 | + # Getting the signed fields for signature. | |
| 490 | + $sig = array(); | |
| 491 | + $signed = explode(',', $this->data['openid_signed']); | |
| 492 | + foreach($signed as $field) { | |
| 493 | + $name = strtr($field, '.', '_'); | |
| 494 | + if(!isset($this->data['openid_' . $name])) { | |
| 495 | + return false; | |
| 496 | + } | |
| 497 | + | |
| 498 | + $sig[$field] = $this->data['openid_' . $name]; | |
| 499 | + } | |
| 500 | + | |
| 501 | + # Computing the signature and checking if it matches. | |
| 502 | + $sig = $this->keyValueForm($sig); | |
| 503 | + if ($this->data['openid_sig'] != | |
| 504 | + base64_encode(hash_hmac($this->assoc['hash'], $sig, $this->assoc['mac'], true)) | |
| 505 | + ) { | |
| 506 | + return false; | |
| 507 | + } | |
| 508 | + | |
| 509 | + # Clearing the nonce, so that it won't be used again. | |
| 510 | + $this->assoc['nonce'] = null; | |
| 511 | + | |
| 512 | + if(empty($this->assoc['private'])) { | |
| 513 | + # Commiting changes to the association. | |
| 514 | + $this->setAssoc($this->assoc['handle'], $this->assoc); | |
| 515 | + } else { | |
| 516 | + # Private associations shouldn't be used again, se we can as well delete them. | |
| 517 | + $this->delAssoc($this->assoc['handle']); | |
| 518 | + } | |
| 519 | + | |
| 520 | + # Nothing has failed, so the verification was a success. | |
| 521 | + return true; | |
| 522 | + } | |
| 523 | + | |
| 524 | + /** | |
| 525 | + * Performs association with an RP. | |
| 526 | + */ | |
| 527 | + protected function associate() | |
| 528 | + { | |
| 529 | + # Rejecting no-encryption without TLS. | |
| 530 | + if(empty($_SERVER['HTTPS']) && $this->data['openid_session_type'] == 'no-encryption') { | |
| 531 | + $this->directErrorResponse(); | |
| 532 | + } | |
| 533 | + | |
| 534 | + # Checking whether we support DH at all. | |
| 535 | + if (!$this->dh && substr($this->data['openid_session_type'], 0, 2) == 'DH') { | |
| 536 | + $this->redirect($this->response(array( | |
| 537 | + 'openid.error' => 'DH not supported', | |
| 538 | + 'openid.error_code' => 'unsupported-type', | |
| 539 | + 'openid.session_type' => 'no-encryption' | |
| 540 | + ))); | |
| 541 | + } | |
| 542 | + | |
| 543 | + # Creating the association | |
| 544 | + $this->assoc = array(); | |
| 545 | + $this->assoc['hash'] = $this->data['openid_assoc_type'] == 'HMAC-SHA256' ? 'sha256' : 'sha1'; | |
| 546 | + $this->assoc['handle'] = $this->assoc_handle(); | |
| 547 | + | |
| 548 | + # Getting the shared secret | |
| 549 | + if($this->data['openid_session_type'] == 'no-encryption') { | |
| 550 | + $this->assoc['mac'] = base64_encode($this->shared_secret($this->assoc['hash'])); | |
| 551 | + } else { | |
| 552 | + $this->dh(); | |
| 553 | + } | |
| 554 | + | |
| 555 | + # Preparing the direct response... | |
| 556 | + $response = array( | |
| 557 | + 'ns' => $this->ns, | |
| 558 | + 'assoc_handle' => $this->assoc['handle'], | |
| 559 | + 'assoc_type' => $this->data['openid_assoc_type'], | |
| 560 | + 'session_type' => $this->data['openid_session_type'], | |
| 561 | + 'expires_in' => $this->assoc_lifetime | |
| 562 | + ); | |
| 563 | + | |
| 564 | + if(isset($this->assoc['dh_server_public'])) { | |
| 565 | + $response['dh_server_public'] = $this->assoc['dh_server_public']; | |
| 566 | + $response['enc_mac_key'] = $this->assoc['mac']; | |
| 567 | + } else { | |
| 568 | + $response['mac_key'] = $this->assoc['mac']; | |
| 569 | + } | |
| 570 | + | |
| 571 | + # ...and sending it. | |
| 572 | + echo $this->keyValueForm($response); | |
| 573 | + die(); | |
| 574 | + } | |
| 575 | + | |
| 576 | + /** | |
| 577 | + * Creates a private association. | |
| 578 | + */ | |
| 579 | + protected function generateAssociation() | |
| 580 | + { | |
| 581 | + $this->assoc = array(); | |
| 582 | + # We use sha1 by default. | |
| 583 | + $this->assoc['hash'] = 'sha1'; | |
| 584 | + $this->assoc['mac'] = $this->shared_secret('sha1'); | |
| 585 | + $this->assoc['handle'] = $this->assoc_handle(); | |
| 586 | + } | |
| 587 | + | |
| 588 | + /** | |
| 589 | + * Encrypts the MAC key using DH key exchange. | |
| 590 | + */ | |
| 591 | + protected function dh() | |
| 592 | + { | |
| 593 | + if(empty($this->data['openid_dh_modulus'])) { | |
| 594 | + $this->data['openid_dh_modulus'] = $this->default_modulus; | |
| 595 | + } | |
| 596 | + | |
| 597 | + if(empty($this->data['openid_dh_gen'])) { | |
| 598 | + $this->data['openid_dh_gen'] = $this->default_gen; | |
| 599 | + } | |
| 600 | + | |
| 601 | + if(empty($this->data['openid_dh_consumer_public'])) { | |
| 602 | + $this->directErrorResponse(); | |
| 603 | + } | |
| 604 | + | |
| 605 | + $modulus = $this->b64dec($this->data['openid_dh_modulus']); | |
| 606 | + $gen = $this->b64dec($this->data['openid_dh_gen']); | |
| 607 | + $consumerKey = $this->b64dec($this->data['openid_dh_consumer_public']); | |
| 608 | + | |
| 609 | + $privateKey = $this->keygen(strlen($modulus)); | |
| 610 | + $publicKey = $this->powmod($gen, $privateKey, $modulus); | |
| 611 | + $ss = $this->powmod($consumerKey, $privateKey, $modulus); | |
| 612 | + | |
| 613 | + $mac = $this->x_or(hash($this->assoc['hash'], $ss, true), $this->shared_secret($this->assoc['hash'])); | |
| 614 | + $this->assoc['dh_server_public'] = $this->decb64($publicKey); | |
| 615 | + $this->assoc['mac'] = base64_encode($mac); | |
| 616 | + } | |
| 617 | + | |
| 618 | + /** | |
| 619 | + * XORs two strings. | |
| 620 | + * @param String $a | |
| 621 | + * @param String $b | |
| 622 | + * @return String $a ^ $b | |
| 623 | + */ | |
| 624 | + protected function x_or($a, $b) | |
| 625 | + { | |
| 626 | + $length = strlen($a); | |
| 627 | + for($i = 0; $i < $length; $i++) { | |
| 628 | + $a[$i] = $a[$i] ^ $b[$i]; | |
| 629 | + } | |
| 630 | + | |
| 631 | + return $a; | |
| 632 | + } | |
| 633 | + | |
| 634 | + /** | |
| 635 | + * Prepares an indirect response url. | |
| 636 | + * @param array $params Parameters to be sent. | |
| 637 | + */ | |
| 638 | + protected function response($params) | |
| 639 | + { | |
| 640 | + $params += array('openid.ns' => $this->ns); | |
| 641 | + return $this->data['openid_return_to'] | |
| 642 | + . (strpos($this->data['openid_return_to'],'?') ? '&' : '?') | |
| 643 | + . http_build_query($params, '', '&'); | |
| 644 | + } | |
| 645 | + | |
| 646 | + /** | |
| 647 | + * Outputs a direct error. | |
| 648 | + */ | |
| 649 | + protected function errorResponse() | |
| 650 | + { | |
| 651 | + if(!empty($this->data['openid_return_to'])) { | |
| 652 | + $response = array( | |
| 653 | + 'openid.mode' => 'error', | |
| 654 | + 'openid.error' => 'Invalid request' | |
| 655 | + ); | |
| 656 | + $this->redirect($this->response($response)); | |
| 657 | + } else { | |
| 658 | + header('HTTP/1.1 400 Bad Request'); | |
| 659 | + $response = array( | |
| 660 | + 'ns' => $this->ns, | |
| 661 | + 'error' => 'Invalid request' | |
| 662 | + ); | |
| 663 | + echo $this->keyValueForm($response); | |
| 664 | + } | |
| 665 | + die(); | |
| 666 | + } | |
| 667 | + | |
| 668 | + /** | |
| 669 | + * Sends an positive assertion. | |
| 670 | + * @param String $identity the OP-Local Identifier that is being authenticated. | |
| 671 | + * @param Array $attributes User attributes to be sent. | |
| 672 | + */ | |
| 673 | + protected function positiveResponse($identity, $attributes) | |
| 674 | + { | |
| 675 | + # We generate a private association if there is none established. | |
| 676 | + if(!$this->assoc) { | |
| 677 | + $this->generateAssociation(); | |
| 678 | + $this->assoc['private'] = true; | |
| 679 | + } | |
| 680 | + | |
| 681 | + # We set openid.identity (and openid.claimed_id if necessary) to our $identity | |
| 682 | + if($this->data['openid_identity'] == $this->data['openid_claimed_id']) { | |
| 683 | + $this->data['openid_claimed_id'] = $identity; | |
| 684 | + } | |
| 685 | + $this->data['openid_identity'] = $identity; | |
| 686 | + | |
| 687 | + # Preparing fields to be signed | |
| 688 | + $params = array( | |
| 689 | + 'op_endpoint' => $this->serverLocation, | |
| 690 | + 'claimed_id' => $this->data['openid_claimed_id'], | |
| 691 | + 'identity' => $this->data['openid_identity'], | |
| 692 | + 'return_to' => $this->data['openid_return_to'], | |
| 693 | + 'realm' => $this->data['openid_realm'], | |
| 694 | + 'response_nonce' => gmdate("Y-m-d\TH:i:s\Z"), | |
| 695 | + 'assoc_handle' => $this->assoc['handle'], | |
| 696 | + ); | |
| 697 | + | |
| 698 | + $params += $this->responseAttributes($attributes); | |
| 699 | + | |
| 700 | + # Has the RP used an invalid association handle? | |
| 701 | + if (isset($this->data['openid_assoc_handle']) | |
| 702 | + && $this->data['openid_assoc_handle'] != $this->assoc['handle'] | |
| 703 | + ) { | |
| 704 | + $params['invalidate_handle'] = $this->data['openid_assoc_handle']; | |
| 705 | + } | |
| 706 | + | |
| 707 | + # Signing the $params | |
| 708 | + $sig = hash_hmac($this->assoc['hash'], $this->keyValueForm($params), $this->assoc['mac'], true); | |
| 709 | + $req = array( | |
| 710 | + 'openid.mode' => 'id_res', | |
| 711 | + 'openid.signed' => implode(',', array_keys($params)), | |
| 712 | + 'openid.sig' => base64_encode($sig), | |
| 713 | + ); | |
| 714 | + | |
| 715 | + # Saving the nonce and commiting the association. | |
| 716 | + $this->assoc['nonce'] = $params['response_nonce']; | |
| 717 | + $this->setAssoc($this->assoc['handle'], $this->assoc); | |
| 718 | + | |
| 719 | + # Preparing and sending the response itself | |
| 720 | + foreach($params as $name => $value) { | |
| 721 | + $req['openid.' . $name] = $value; | |
| 722 | + } | |
| 723 | + | |
| 724 | + $this->redirect($this->response($req)); | |
| 725 | + } | |
| 726 | + | |
| 727 | + /** | |
| 728 | + * Prepares an array of attributes to send | |
| 729 | + */ | |
| 730 | + protected function responseAttributes($attributes) | |
| 731 | + { | |
| 732 | + if(!$attributes) return array(); | |
| 733 | + | |
| 734 | + $ns = 'http://axschema.org/'; | |
| 735 | + | |
| 736 | + $response = array(); | |
| 737 | + if(isset($this->data['ax'])) { | |
| 738 | + $response['ns.ax'] = 'http://openid.net/srv/ax/1.0'; | |
| 739 | + foreach($attributes as $name => $value) { | |
| 740 | + $alias = strtr($name, '/', '_'); | |
| 741 | + $response['ax.type.' . $alias] = $ns . $name; | |
| 742 | + $response['ax.value.' . $alias] = $value; | |
| 743 | + } | |
| 744 | + return $response; | |
| 745 | + } | |
| 746 | + | |
| 747 | + foreach($attributes as $name => $value) { | |
| 748 | + if(!isset($this->ax_to_sreg[$name])) { | |
| 749 | + continue; | |
| 750 | + } | |
| 751 | + | |
| 752 | + $response['sreg.' . $this->ax_to_sreg[$name]] = $value; | |
| 753 | + } | |
| 754 | + return $response; | |
| 755 | + } | |
| 756 | + | |
| 757 | + /** | |
| 758 | + * Encodes fields in key-value form. | |
| 759 | + * @param Array $params Fields to be encoded. | |
| 760 | + * @return String $params in key-value form. | |
| 761 | + */ | |
| 762 | + protected function keyValueForm($params) | |
| 763 | + { | |
| 764 | + $str = ''; | |
| 765 | + foreach($params as $name => $value) { | |
| 766 | + $str .= "$name:$value\n"; | |
| 767 | + } | |
| 768 | + | |
| 769 | + return $str; | |
| 770 | + } | |
| 771 | + | |
| 772 | + /** | |
| 773 | + * Responds with an information that the user has canceled authentication. | |
| 774 | + */ | |
| 775 | + protected function cancel() | |
| 776 | + { | |
| 777 | + $this->redirect($this->response(array('openid.mode' => 'cancel'))); | |
| 778 | + } | |
| 779 | + | |
| 780 | + /** | |
| 781 | + * Converts base64 encoded number to it's decimal representation. | |
| 782 | + * @param String $str base64 encoded number. | |
| 783 | + * @return String Decimal representation of that number. | |
| 784 | + */ | |
| 785 | + protected function b64dec($str) | |
| 786 | + { | |
| 787 | + $bytes = unpack('C*', base64_decode($str)); | |
| 788 | + $n = 0; | |
| 789 | + foreach($bytes as $byte) { | |
| 790 | + $n = $this->add($this->mul($n, 256), $byte); | |
| 791 | + } | |
| 792 | + | |
| 793 | + return $n; | |
| 794 | + } | |
| 795 | + | |
| 796 | + /** | |
| 797 | + * Complements b64dec. | |
| 798 | + */ | |
| 799 | + protected function decb64($num) | |
| 800 | + { | |
| 801 | + $bytes = array(); | |
| 802 | + while($num) { | |
| 803 | + array_unshift($bytes, $this->mod($num, 256)); | |
| 804 | + $num = $this->div($num, 256); | |
| 805 | + } | |
| 806 | + | |
| 807 | + if($bytes && $bytes[0] > 127) { | |
| 808 | + array_unshift($bytes,0); | |
| 809 | + } | |
| 810 | + | |
| 811 | + array_unshift($bytes, 'C*'); | |
| 812 | + | |
| 813 | + return base64_encode(call_user_func_array('pack', $bytes)); | |
| 814 | + } | |
| 815 | + | |
| 816 | + function __call($name, $args) | |
| 817 | + { | |
| 818 | + switch($name) { | |
| 819 | + case 'add': | |
| 820 | + case 'mul': | |
| 821 | + case 'pow': | |
| 822 | + case 'mod': | |
| 823 | + case 'div': | |
| 824 | + case 'powmod': | |
| 825 | + if(function_exists('gmp_strval')) { | |
| 826 | + return gmp_strval(call_user_func_array($this->$name, $args)); | |
| 827 | + } | |
| 828 | + return call_user_func_array($this->$name, $args); | |
| 829 | + default: | |
| 830 | + throw new BadMethodCallException(); | |
| 831 | + } | |
| 832 | + } | |
| 833 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,120 @@ |
| 1 | +TwitterOAuth documentation. | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | +GET THE CODE | |
| 6 | +==================== | |
| 7 | +You can pull the latest development version using git: | |
| 8 | +git clone git://github.com/abraham/twitteroauth.git | |
| 9 | + | |
| 10 | +Or you can download the latest release by visiting: | |
| 11 | +http://github.com/abraham/twitteroauth/downloads | |
| 12 | + | |
| 13 | + | |
| 14 | +FLOW OVERVIEW | |
| 15 | +==================== | |
| 16 | +1) Build TwitterOAuth object using client credentials. | |
| 17 | +2) Request temporary credentials from Twitter. | |
| 18 | +3) Build authorize URL for Twitter. | |
| 19 | +4) Redirect user to authorize URL. | |
| 20 | +5) User authorizes access and returns from Twitter. | |
| 21 | +6) Rebuild TwitterOAuth object with client credentials and temporary credentials. | |
| 22 | +7) Get token credentials from Twitter. | |
| 23 | +8) Rebuild TwitterOAuth object with client credentials and token credentials. | |
| 24 | +9) Query Twitter API. | |
| 25 | + | |
| 26 | + | |
| 27 | +TERMINOLOGY | |
| 28 | +==================== | |
| 29 | +The terminology has changed since 0.1.x to better match the draft-hammer-oauth IETF | |
| 30 | +RFC. You can read that at http://tools.ietf.org/html/draft-hammer-oauth. Some of the | |
| 31 | +terms will differ from those Twitter uses as well. | |
| 32 | + | |
| 33 | +client credentials - Consumer key/secret you get when registering an app with Twitter. | |
| 34 | +temporary credentials - Previously known as the request token. | |
| 35 | +token credentials - Previously known as the access token. | |
| 36 | + | |
| 37 | + | |
| 38 | +PARAMETERS | |
| 39 | +==================== | |
| 40 | +There are a number of parameters you can modify after creating a TwitterOAuth object. | |
| 41 | + | |
| 42 | +Switch to XML instead of JSON. | |
| 43 | +$connection->format = 'xml'; | |
| 44 | + | |
| 45 | +Stop auto decoding JSON. | |
| 46 | +$connection->decode_json = FALSE; | |
| 47 | + | |
| 48 | +Custom useragent. | |
| 49 | +$connection->useragent = 'Custom useragent string'; | |
| 50 | + | |
| 51 | +Verify Twitters SSL certificate. | |
| 52 | +$connection->ssl_verifypeer = TRUE; | |
| 53 | + | |
| 54 | +There are several more you can find in TwitterOAuth.php. | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | +EXTENDED FLOW USING EXAMPLE CODE | |
| 59 | +==================== | |
| 60 | +To use TwitterOAuth with the Twitter API you need TwitterOAuth.php, OAuth.php and | |
| 61 | +client credentials. You can get client credentials by registering your application at | |
| 62 | +https://twitter.com/apps. | |
| 63 | + | |
| 64 | +The example files are explained below. | |
| 65 | + | |
| 66 | +0) Users start out on connect.php which displays the "Sign in with Twitter" image hyperlinked | |
| 67 | +to redirect.php. This button should be displayed on your homepage in your login section. The | |
| 68 | +client credentials are saved in config.php as CONSUMER_KEY and CONSUMER_SECRET. You can | |
| 69 | +save a static callback URL in the app settings page, in the config file or use a dynamic | |
| 70 | +callback URL later in step 2. In example use http://example.com/callback.php. | |
| 71 | + | |
| 72 | +1) When a user lands on redirect.php we build a new TwitterOAuth object using the client | |
| 73 | +credentials. If you have your own configuration method feel free to use it instead of config.php. | |
| 74 | +$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);// Use config.php client credentials | |
| 75 | +$connection = new TwitterOAuth('abc890', '123xyz'); | |
| 76 | + | |
| 77 | +2) Using the built $connection object you will ask Twitter for temporary credentials. If you | |
| 78 | +wish to have a dynamic callback URL for each user you can do pass a URL as a parameter. | |
| 79 | +$temporary_credentials = $connection->getRequestToken(); // Use applications registered callback. | |
| 80 | +$temporary_credentials = $connection->getRequestToken('http://example.com/callback.php?'); | |
| 81 | + | |
| 82 | +3) Now that we have temporary credentials the user has to go to Twitter and authorize the app | |
| 83 | +to access and updates their data. You can also pass a second parameter of FALSE to not use Sign | |
| 84 | +in with Twitter: http://apiwiki.twitter.com/Sign-in-with-Twitter. | |
| 85 | +$redirect_url = $connection->getAuthorizeURL($temporary_credentials); // Use Sign in with Twitter | |
| 86 | +$redirect_url = $connection->getAuthorizeURL($temporary_credentials, FALSE); | |
| 87 | + | |
| 88 | +4) You will now have a Twitter URL that you must send the user to. You can add parameters and | |
| 89 | +they will return with the user in step 5. | |
| 90 | +https://twitter.com/oauth/authenticate?oauth_token=xyz123 | |
| 91 | +https://twitter.com/oauth/authenticate?oauth_token=xyz123&info=abc // info will return with user | |
| 92 | + | |
| 93 | +5) The user is now on twitter.com and may have to login. Once authenticated with Twitter they will | |
| 94 | +will either have to click on allow/deny, or will be automatically redirected back to the callback. | |
| 95 | + | |
| 96 | +6) Now that the user has returned to callback.php and allowed access we need to build a new | |
| 97 | +TwitterOAuth object using the temporary credentials. | |
| 98 | +$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_SESSION['oauth_token'], | |
| 99 | +$_SESSION['oauth_token_secret']); | |
| 100 | + | |
| 101 | +7) Now we ask Twitter for long lasting token credentials. These are specific to the application | |
| 102 | +and user and will act like password to make future requests. If a dynamic callback URL was used | |
| 103 | +you will also have to pass the oauth_varifier parameter. Normally the token credentials would | |
| 104 | +get saved in your database but for this example we are just using sessions. | |
| 105 | +$token_credentials = $connection->getAccessToken(); // Used applications registered callback URL | |
| 106 | +$token_credentials = $connection->getAccessToken($_REQUEST['oauth_verifier']); | |
| 107 | + | |
| 108 | +7a) After getting the token credentials we redirect the user to index.php. | |
| 109 | + | |
| 110 | +8) With the token credentials we build a new TwitterOAuth object. | |
| 111 | +$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $token_credentials['oauth_token'], | |
| 112 | +$token_credentials['oauth_token_secret']); | |
| 113 | + | |
| 114 | +9) And finally we can make requests authenticated as the user. You can GET, POST, and DELETE API | |
| 115 | +methods. Directly copy the path from the API documentation and add an array of any parameter | |
| 116 | +you wish to include for the API method such as curser or in_reply_to_status_id. | |
| 117 | +$content = $connection->get('account/verify_credentials'); | |
| 118 | +$connection->post('statuses/update', array('status' => 'Text of status here', | |
| 119 | +'in_reply_to_status_id' => 123456)); | |
| 120 | +$content = $connection->delete('statuses/destroy/12345'); | |
| 0 | 121 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | +Copyright (c) 2009 Abraham Williams - http://abrah.am - abraham@poseurte.ch | |
| 2 | + | |
| 3 | +Permission is hereby granted, free of charge, to any person | |
| 4 | +obtaining a copy of this software and associated documentation | |
| 5 | +files (the "Software"), to deal in the Software without | |
| 6 | +restriction, including without limitation the rights to use, | |
| 7 | +copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | +copies of the Software, and to permit persons to whom the | |
| 9 | +Software is furnished to do so, subject to the following | |
| 10 | +conditions: | |
| 11 | + | |
| 12 | +The above copyright notice and this permission notice shall be | |
| 13 | +included in all copies or substantial portions of the Software. | |
| 14 | + | |
| 15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 16 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
| 17 | +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 18 | +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
| 19 | +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
| 20 | +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 21 | +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
| 22 | +OTHER DEALINGS IN THE SOFTWARE. | ... | ... |
| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | +Abraham Williams | abraham@poseurte.ch | http://abrah.am | @abraham | |
| 2 | + | |
| 3 | +The first PHP library for working with Twitter's OAuth API. | |
| 4 | + | |
| 5 | +Documentation: http://wiki.github.com/abraham/twitteroauth/documentation | |
| 6 | +Source: http://github.com/abraham/twitteroauth | |
| 7 | +Twitter: http://apiwiki.twitter.com | ... | ... |
| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * @file | |
| 4 | + * Take the user when they return from Twitter. Get access tokens. | |
| 5 | + * Verify credentials and redirect to based on response from Twitter. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +/* Start session and load lib */ | |
| 9 | +session_name("openid"); | |
| 10 | +session_start(); | |
| 11 | +require_once('twitteroauth/twitteroauth.php'); | |
| 12 | +require_once('config.php'); | |
| 13 | + | |
| 14 | +/* If the oauth_token is old redirect to the connect page. */ | |
| 15 | +if (isset($_REQUEST['oauth_token']) && $_SESSION['oauth_token'] !== $_REQUEST['oauth_token']) { | |
| 16 | + $_SESSION['oauth_status'] = 'oldtoken'; | |
| 17 | + header('Location: ./clearsessions.php'); | |
| 18 | +} | |
| 19 | + | |
| 20 | +/* Create TwitteroAuth object with app key/secret and token key/secret from default phase */ | |
| 21 | +$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']); | |
| 22 | + | |
| 23 | +/* Request access tokens from twitter */ | |
| 24 | +$access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']); | |
| 25 | + | |
| 26 | +/* Save the access tokens. Normally these would be saved in a database for future use. */ | |
| 27 | +$_SESSION['access_token'] = $access_token; | |
| 28 | + | |
| 29 | +/* Remove no longer needed request tokens */ | |
| 30 | +unset($_SESSION['oauth_token']); | |
| 31 | +unset($_SESSION['oauth_token_secret']); | |
| 32 | + | |
| 33 | +/* If HTTP response is 200 continue otherwise send to connect page to retry */ | |
| 34 | +if (200 == $connection->http_code) { | |
| 35 | + /* The user has been verified and the access tokens can be saved for future use */ | |
| 36 | + $_SESSION['status'] = 'verified'; | |
| 37 | + header('Location: ./index.php'); | |
| 38 | +} else { | |
| 39 | + /* Save HTTP status for error dialog on connnect page.*/ | |
| 40 | + header('Location: ./clearsessions.php'); | |
| 41 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * @file | |
| 4 | + * Clears PHP sessions and redirects to the connect page. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +/* Load and clear sessions */ | |
| 8 | +session_start("openid"); | |
| 9 | +session_destroy(); | |
| 10 | + | |
| 11 | +/* Redirect to page with the connect to Twitter option. */ | |
| 12 | +header('Location: ../openid/login.php?login&erro=ok'); | |
| 13 | +?> | |
| 0 | 14 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * @file | |
| 5 | + * A single location to store configuration. | |
| 6 | + */ | |
| 7 | +include_once("../../ms_configura.php"); | |
| 8 | +define('CONSUMER_KEY', $twitteroauth["consumerkey"]); | |
| 9 | +define('CONSUMER_SECRET', $twitteroauth["consumersecret"]); | |
| 10 | +$protocolo = explode("/",$_SERVER['SERVER_PROTOCOL']); | |
| 11 | +$urlaplic = strtolower($protocolo[0])."://".$_SERVER['HTTP_HOST']."/".basename($locaplic); | |
| 12 | +define('OAUTH_CALLBACK', $urlaplic."/pacotes/twitteroauth/callback.php"); | |
| 13 | +?> | |
| 0 | 14 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * @file | |
| 5 | + * Check if consumer token is set and if so send user to get a request token. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * Exit with an error message if the CONSUMER_KEY or CONSUMER_SECRET is not defined. | |
| 10 | + */ | |
| 11 | +//require_once('config.php'); | |
| 12 | +//include_once("redirect.php"); | |
| 13 | +/* | |
| 14 | +if (CONSUMER_KEY === '' || CONSUMER_SECRET === '') { | |
| 15 | + echo 'You need a consumer key and secret to test the sample code. Get one from <a href="https://twitter.com/apps">https://twitter.com/apps</a>'; | |
| 16 | + exit; | |
| 17 | +} | |
| 18 | +*/ | |
| 19 | +// Build an image link to start the redirect process. */ | |
| 20 | +//$content = '<a href="./redirect.php"><img src="./images/lighter.png" alt="Sign in with Twitter"/></a>'; | |
| 21 | + | |
| 22 | +/* Include HTML to display on the page. */ | |
| 23 | +//include('html.inc'); | ... | ... |
| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |
| 2 | + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
| 3 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |
| 4 | + <head> | |
| 5 | + <title>Twitter OAuth in PHP</title> | |
| 6 | + <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> | |
| 7 | + <style type="text/css"> | |
| 8 | + img {border-width: 0} | |
| 9 | + * {font-family:'Lucida Grande', sans-serif;} | |
| 10 | + </style> | |
| 11 | + </head> | |
| 12 | + <body> | |
| 13 | + <div> | |
| 14 | + <h2>Welcome to a Twitter OAuth PHP example.</h2> | |
| 15 | + | |
| 16 | + <p>This site is a basic showcase of Twitters OAuth authentication method. If you are having issues try <a href='./clearsessions.php'>clearing your session</a>.</p> | |
| 17 | + | |
| 18 | + <p> | |
| 19 | + Links: | |
| 20 | + <a href='http://github.com/abraham/twitteroauth'>Source Code</a> & | |
| 21 | + <a href='http://wiki.github.com/abraham/twitteroauth/documentation'>Documentation</a> | | |
| 22 | + Contact @<a href='http://twitter.com/abraham'>abraham</a> | |
| 23 | + </p> | |
| 24 | + <hr /> | |
| 25 | + <?php if (isset($menu)) { ?> | |
| 26 | + <?php echo $menu; ?> | |
| 27 | + <?php } ?> | |
| 28 | + </div> | |
| 29 | + <?php if (isset($status_text)) { ?> | |
| 30 | + <?php echo '<h3>'.$status_text.'</h3>'; ?> | |
| 31 | + <?php } ?> | |
| 32 | + <p> | |
| 33 | + <pre> | |
| 34 | + <?php print_r($content); ?> | |
| 35 | + </pre> | |
| 36 | + </p> | |
| 37 | + | |
| 38 | + </body> | |
| 39 | +</html> | ... | ... |
| ... | ... | @@ -0,0 +1,793 @@ |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
| 7 | + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
| 8 | + | |
| 9 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |
| 10 | + <head> | |
| 11 | + <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> | |
| 12 | + <meta http-equiv="X-UA-Compatible" content="chrome=1"> | |
| 13 | + <title>images/darker.png at master from abraham's twitteroauth - GitHub</title> | |
| 14 | + <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub" /> | |
| 15 | + <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub" /> | |
| 16 | + | |
| 17 | + <link href="https://assets1.github.com/stylesheets/bundle_common.css?6847bdee64e5b0e2ee04e4e961f33e28593984a2" media="screen" rel="stylesheet" type="text/css" /> | |
| 18 | +<link href="https://assets0.github.com/stylesheets/bundle_github.css?6847bdee64e5b0e2ee04e4e961f33e28593984a2" media="screen" rel="stylesheet" type="text/css" /> | |
| 19 | + | |
| 20 | + <script type="text/javascript" charset="utf-8"> | |
| 21 | + var GitHub = {} | |
| 22 | + var github_user = null | |
| 23 | + | |
| 24 | + </script> | |
| 25 | + <script src="https://assets2.github.com/javascripts/jquery/jquery-1.4.2.min.js?6847bdee64e5b0e2ee04e4e961f33e28593984a2" type="text/javascript"></script> | |
| 26 | + <script src="https://assets3.github.com/javascripts/bundle_common.js?6847bdee64e5b0e2ee04e4e961f33e28593984a2" type="text/javascript"></script> | |
| 27 | +<script src="https://assets3.github.com/javascripts/bundle_github.js?6847bdee64e5b0e2ee04e4e961f33e28593984a2" type="text/javascript"></script> | |
| 28 | + | |
| 29 | + <script type="text/javascript" charset="utf-8"> | |
| 30 | + GitHub.spy({ | |
| 31 | + repo: "abraham/twitteroauth" | |
| 32 | + }) | |
| 33 | + </script> | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + <link href="https://github.com/abraham/twitteroauth/commits/master.atom" rel="alternate" title="Recent Commits to twitteroauth:master" type="application/atom+xml" /> | |
| 41 | + | |
| 42 | + <meta name="description" content="The first PHP Library to support OAuth for Twitter's REST API." /> | |
| 43 | + <script type="text/javascript"> | |
| 44 | + GitHub.nameWithOwner = GitHub.nameWithOwner || "abraham/twitteroauth"; | |
| 45 | + GitHub.currentRef = 'master'; | |
| 46 | + </script> | |
| 47 | + | |
| 48 | + | |
| 49 | + <script type="text/javascript"> | |
| 50 | + var _gaq = _gaq || []; | |
| 51 | + _gaq.push(['_setAccount', 'UA-3769691-2']); | |
| 52 | + _gaq.push(['_trackPageview']); | |
| 53 | + (function() { | |
| 54 | + var ga = document.createElement('script'); | |
| 55 | + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | |
| 56 | + ga.setAttribute('async', 'true'); | |
| 57 | + document.documentElement.firstChild.appendChild(ga); | |
| 58 | + })(); | |
| 59 | + </script> | |
| 60 | + | |
| 61 | + </head> | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + <body class="logged_out "> | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + <script type="text/javascript"> | |
| 70 | + var _kmq = _kmq || []; | |
| 71 | + function _kms(u){ | |
| 72 | + var s = document.createElement('script'); var f = document.getElementsByTagName('script')[0]; s.type = 'text/javascript'; s.async = true; | |
| 73 | + s.src = u; f.parentNode.insertBefore(s, f); | |
| 74 | + } | |
| 75 | + _kms('//i.kissmetrics.com/i.js');_kms('//doug1izaerwt3.cloudfront.net/406e8bf3a2b8846ead55afb3cfaf6664523e3a54.1.js'); | |
| 76 | + </script> | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + <div class="subnavd" id="main"> | |
| 86 | + <div id="header" class="true"> | |
| 87 | + | |
| 88 | + <a class="logo boring" href="https://github.com"> | |
| 89 | + <img src="/images/modules/header/logov3.png?changed" class="default" alt="github" /> | |
| 90 | + <![if !IE]> | |
| 91 | + <img src="/images/modules/header/logov3-hover.png" class="hover" alt="github" /> | |
| 92 | + <![endif]> | |
| 93 | + </a> | |
| 94 | + | |
| 95 | + | |
| 96 | + <div class="topsearch"> | |
| 97 | + | |
| 98 | + <ul class="nav logged_out"> | |
| 99 | + <li><a href="https://github.com">Home</a></li> | |
| 100 | + <li class="pricing"><a href="/plans">Pricing and Signup</a></li> | |
| 101 | + <li><a href="https://github.com/training">Training</a></li> | |
| 102 | + <li><a href="https://gist.github.com">Gist</a></li> | |
| 103 | + <li><a href="/blog">Blog</a></li> | |
| 104 | + <li><a href="https://github.com/login">Login</a></li> | |
| 105 | + </ul> | |
| 106 | + | |
| 107 | +</div> | |
| 108 | + | |
| 109 | + </div> | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + <div class="site"> | |
| 115 | + <div class="pagehead repohead vis-public "> | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + <div class="title-actions-bar"> | |
| 120 | + <h1> | |
| 121 | + <a href="/abraham">abraham</a> / <strong><a href="https://github.com/abraham/twitteroauth">twitteroauth</a></strong> | |
| 122 | + | |
| 123 | + | |
| 124 | + </h1> | |
| 125 | + | |
| 126 | + | |
| 127 | + <ul class="actions"> | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + <li class="for-owner" style="display:none"><a href="https://github.com/abraham/twitteroauth/admin" class="minibutton btn-admin "><span><span class="icon"></span>Admin</span></a></li> | |
| 132 | + <li> | |
| 133 | + <a href="/abraham/twitteroauth/toggle_watch" class="minibutton btn-watch " id="watch_button" onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '0788e12631f37df2bd75592390a297816b6698da'); f.appendChild(s);f.submit();return false;" style="display:none"><span><span class="icon"></span>Watch</span></a> | |
| 134 | + <a href="/abraham/twitteroauth/toggle_watch" class="minibutton btn-watch " id="unwatch_button" onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '0788e12631f37df2bd75592390a297816b6698da'); f.appendChild(s);f.submit();return false;" style="display:none"><span><span class="icon"></span>Unwatch</span></a> | |
| 135 | + </li> | |
| 136 | + | |
| 137 | + | |
| 138 | + <li class="for-notforked" style="display:none"><a href="/abraham/twitteroauth/fork" class="minibutton btn-fork " id="fork_button" onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '0788e12631f37df2bd75592390a297816b6698da'); f.appendChild(s);f.submit();return false;"><span><span class="icon"></span>Fork</span></a></li> | |
| 139 | + <li class="for-hasfork" style="display:none"><a href="#" class="minibutton btn-fork " id="your_fork_button"><span><span class="icon"></span>Your Fork</span></a></li> | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + <li class="repostats"> | |
| 147 | + <ul class="repo-stats"> | |
| 148 | + <li class="watchers"><a href="/abraham/twitteroauth/watchers" title="Watchers" class="tooltipped downwards">591</a></li> | |
| 149 | + <li class="forks"><a href="/abraham/twitteroauth/network" title="Forks" class="tooltipped downwards">79</a></li> | |
| 150 | + </ul> | |
| 151 | + </li> | |
| 152 | + </ul> | |
| 153 | + | |
| 154 | + </div> | |
| 155 | + | |
| 156 | + | |
| 157 | + <ul class="tabs"> | |
| 158 | + <li><a href="https://github.com/abraham/twitteroauth/tree/master" class="selected" highlight="repo_source">Source</a></li> | |
| 159 | + <li><a href="https://github.com/abraham/twitteroauth/commits/master" highlight="repo_commits">Commits</a></li> | |
| 160 | + <li><a href="/abraham/twitteroauth/network" highlight="repo_network">Network</a></li> | |
| 161 | + <li><a href="/abraham/twitteroauth/pulls" highlight="repo_pulls">Pull Requests (4)</a></li> | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + <li><a href="/abraham/twitteroauth/issues" highlight="issues">Issues (34)</a></li> | |
| 168 | + | |
| 169 | + | |
| 170 | + <li><a href="/abraham/twitteroauth/wiki" highlight="repo_wiki">Wiki (3)</a></li> | |
| 171 | + | |
| 172 | + <li><a href="/abraham/twitteroauth/graphs" highlight="repo_graphs">Graphs</a></li> | |
| 173 | + | |
| 174 | + <li class="contextswitch nochoices"> | |
| 175 | + <span class="toggle leftwards" > | |
| 176 | + <em>Branch:</em> | |
| 177 | + <code>master</code> | |
| 178 | + </span> | |
| 179 | + </li> | |
| 180 | + </ul> | |
| 181 | + | |
| 182 | + <div style="display:none" id="pl-description"><p><em class="placeholder">click here to add a description</em></p></div> | |
| 183 | + <div style="display:none" id="pl-homepage"><p><em class="placeholder">click here to add a homepage</em></p></div> | |
| 184 | + | |
| 185 | + <div class="subnav-bar"> | |
| 186 | + | |
| 187 | + <ul> | |
| 188 | + <li> | |
| 189 | + <a href="#" class="dropdown">Switch Branches (3)</a> | |
| 190 | + <ul> | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + <li><a href="/abraham/twitteroauth/blob/0.2.0/images/darker.png" action="show">0.2.0</a></li> | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + <li><a href="/abraham/twitteroauth/blob/gh-pages/images/darker.png" action="show">gh-pages</a></li> | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + <li><strong>master ✓</strong></li> | |
| 204 | + | |
| 205 | + </ul> | |
| 206 | + </li> | |
| 207 | + <li> | |
| 208 | + <a href="#" class="dropdown ">Switch Tags (5)</a> | |
| 209 | + <ul> | |
| 210 | + | |
| 211 | + <li><a href="/abraham/twitteroauth/blob/0.2.0-beta3/images/darker.png">0.2.0-beta3</a></li> | |
| 212 | + | |
| 213 | + | |
| 214 | + <li><a href="/abraham/twitteroauth/blob/0.2.0-beta2/images/darker.png">0.2.0-beta2</a></li> | |
| 215 | + | |
| 216 | + | |
| 217 | + <li><a href="/abraham/twitteroauth/blob/0.2.0-beta/images/darker.png">0.2.0-beta</a></li> | |
| 218 | + | |
| 219 | + | |
| 220 | + <li><a href="/abraham/twitteroauth/blob/0.1.1/images/darker.png">0.1.1</a></li> | |
| 221 | + | |
| 222 | + | |
| 223 | + <li><a href="/abraham/twitteroauth/blob/0.1.0/images/darker.png">0.1.0</a></li> | |
| 224 | + | |
| 225 | + </ul> | |
| 226 | + | |
| 227 | + </li> | |
| 228 | + <li> | |
| 229 | + | |
| 230 | + <a href="/abraham/twitteroauth/branches" class="manage">Branch List</a> | |
| 231 | + | |
| 232 | + </li> | |
| 233 | + </ul> | |
| 234 | +</div> | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + <div id="repo_details" class="metabox clearfix"> | |
| 247 | + <div id="repo_details_loader" class="metabox-loader" style="display:none">Sending Request…</div> | |
| 248 | + | |
| 249 | + <a href="/abraham/twitteroauth/downloads" class="download-source" id="download_button" title="Download source, tagged packages and binaries."><span class="icon"></span>Downloads</a> | |
| 250 | + | |
| 251 | + <div id="repository_desc_wrapper"> | |
| 252 | + <div id="repository_description" rel="repository_description_edit"> | |
| 253 | + | |
| 254 | + <p>The first PHP Library to support OAuth for Twitter's REST API. | |
| 255 | + <span id="read_more" style="display:none">— <a href="#readme">Read more</a></span> | |
| 256 | + </p> | |
| 257 | + | |
| 258 | + </div> | |
| 259 | + | |
| 260 | + <div id="repository_description_edit" style="display:none;" class="inline-edit"> | |
| 261 | + <form action="/abraham/twitteroauth/admin/update" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="0788e12631f37df2bd75592390a297816b6698da" /></div> | |
| 262 | + <input type="hidden" name="field" value="repository_description"> | |
| 263 | + <input type="text" class="textfield" name="value" value="The first PHP Library to support OAuth for Twitter's REST API."> | |
| 264 | + <div class="form-actions"> | |
| 265 | + <button class="minibutton"><span>Save</span></button> <a href="#" class="cancel">Cancel</a> | |
| 266 | + </div> | |
| 267 | + </form> | |
| 268 | + </div> | |
| 269 | + | |
| 270 | + | |
| 271 | + <div class="repository-homepage" id="repository_homepage" rel="repository_homepage_edit"> | |
| 272 | + <p><a href="http://twitteroauth.labs.poseurtech.com" rel="nofollow">http://twitteroauth.labs.poseurtech.com</a></p> | |
| 273 | + </div> | |
| 274 | + | |
| 275 | + <div id="repository_homepage_edit" style="display:none;" class="inline-edit"> | |
| 276 | + <form action="/abraham/twitteroauth/admin/update" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="0788e12631f37df2bd75592390a297816b6698da" /></div> | |
| 277 | + <input type="hidden" name="field" value="repository_homepage"> | |
| 278 | + <input type="text" class="textfield" name="value" value="http://twitteroauth.labs.poseurtech.com"> | |
| 279 | + <div class="form-actions"> | |
| 280 | + <button class="minibutton"><span>Save</span></button> <a href="#" class="cancel">Cancel</a> | |
| 281 | + </div> | |
| 282 | + </form> | |
| 283 | + </div> | |
| 284 | + </div> | |
| 285 | + <div class="rule "></div> | |
| 286 | + <div id="url_box" class="url-box"> | |
| 287 | + <ul class="clone-urls"> | |
| 288 | + | |
| 289 | + | |
| 290 | + <li id="http_clone_url"><a href="https://github.com/abraham/twitteroauth.git" data-permissions="Read-Only">HTTP</a></li> | |
| 291 | + <li id="public_clone_url"><a href="git://github.com/abraham/twitteroauth.git" data-permissions="Read-Only">Git Read-Only</a></li> | |
| 292 | + | |
| 293 | + | |
| 294 | + </ul> | |
| 295 | + <input type="text" spellcheck="false" id="url_field" class="url-field" /> | |
| 296 | + <span style="display:none" id="url_box_clippy"></span> | |
| 297 | + <span id="clippy_tooltip_url_box_clippy" class="clippy-tooltip tooltipped" title="copy to clipboard"> | |
| 298 | + <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" | |
| 299 | + width="14" | |
| 300 | + height="14" | |
| 301 | + class="clippy" | |
| 302 | + id="clippy" > | |
| 303 | + <param name="movie" value="https://assets2.github.com/flash/clippy.swf?v5"/> | |
| 304 | + <param name="allowScriptAccess" value="always" /> | |
| 305 | + <param name="quality" value="high" /> | |
| 306 | + <param name="scale" value="noscale" /> | |
| 307 | + <param NAME="FlashVars" value="id=url_box_clippy&copied=&copyto="> | |
| 308 | + <param name="bgcolor" value="#FFFFFF"> | |
| 309 | + <param name="wmode" value="opaque"> | |
| 310 | + <embed src="https://assets2.github.com/flash/clippy.swf?v5" | |
| 311 | + width="14" | |
| 312 | + height="14" | |
| 313 | + name="clippy" | |
| 314 | + quality="high" | |
| 315 | + allowScriptAccess="always" | |
| 316 | + type="application/x-shockwave-flash" | |
| 317 | + pluginspage="http://www.macromedia.com/go/getflashplayer" | |
| 318 | + FlashVars="id=url_box_clippy&copied=&copyto=" | |
| 319 | + bgcolor="#FFFFFF" | |
| 320 | + wmode="opaque" | |
| 321 | + /> | |
| 322 | + </object> | |
| 323 | + </span> | |
| 324 | + | |
| 325 | + <p id="url_description">This URL has <strong>Read+Write</strong> access</p> | |
| 326 | + </div> | |
| 327 | + </div> | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + </div><!-- /.pagehead --> | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | +<script type="text/javascript"> | |
| 345 | + GitHub.currentCommitRef = 'master' | |
| 346 | + GitHub.currentRepoOwner = 'abraham' | |
| 347 | + GitHub.currentRepo = "twitteroauth" | |
| 348 | + GitHub.downloadRepo = '/abraham/twitteroauth/archives/master' | |
| 349 | + GitHub.revType = "master" | |
| 350 | + | |
| 351 | + GitHub.controllerName = "blob" | |
| 352 | + GitHub.actionName = "show" | |
| 353 | + GitHub.currentAction = "blob#show" | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | +</script> | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + <div id="commit"> | |
| 368 | + <div class="group"> | |
| 369 | + | |
| 370 | + <div class="envelope commit"> | |
| 371 | + <div class="human"> | |
| 372 | + | |
| 373 | + <div class="message"><pre><a href="/abraham/twitteroauth/commit/76446fa719466c09b20fe021bf9e92f54afc43e1">Added getXAuthToken method, updated documentation and fixed some spelling issues.</a> </pre></div> | |
| 374 | + | |
| 375 | + | |
| 376 | + <div class="actor"> | |
| 377 | + <div class="gravatar"> | |
| 378 | + | |
| 379 | + <img src="https://secure.gravatar.com/avatar/cfc268557922ae6f5464a8cb337ceac2?s=140&d=https%3A%2F%2Fgithub.com%2Fimages%2Fgravatars%2Fgravatar-140.png" alt="" width="30" height="30" /> | |
| 380 | + </div> | |
| 381 | + <div class="name"><a href="/abraham">abraham</a> <span>(author)</span></div> | |
| 382 | + <div class="date"> | |
| 383 | + <abbr class="relatize" title="2010-03-10 18:51:58">Wed Mar 10 18:51:58 -0800 2010</abbr> | |
| 384 | + </div> | |
| 385 | + </div> | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + </div> | |
| 390 | + <div class="machine"> | |
| 391 | + <span>c</span>ommit <a href="/abraham/twitteroauth/commit/76446fa719466c09b20fe021bf9e92f54afc43e1" hotkey="c">76446fa719466c09b20f</a><br /> | |
| 392 | + <span>t</span>ree <a href="/abraham/twitteroauth/tree/76446fa719466c09b20fe021bf9e92f54afc43e1" hotkey="t">140d535db90866cac2a7</a><br /> | |
| 393 | + | |
| 394 | + <span>p</span>arent | |
| 395 | + | |
| 396 | + <a href="/abraham/twitteroauth/tree/8da02a678b9c408eb8ca1ffd9c38323f2da632a5" hotkey="p">8da02a678b9c408eb8ca</a> | |
| 397 | + | |
| 398 | + | |
| 399 | + </div> | |
| 400 | + </div> | |
| 401 | + | |
| 402 | + </div> | |
| 403 | + </div> | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + <div id="path"> | |
| 409 | + <b><a href="/abraham/twitteroauth/tree/master">twitteroauth</a></b> / <a href="/abraham/twitteroauth/tree/master/images">images</a> / darker.png <span style="display:none" id="clippy_4055">images/darker.png</span> | |
| 410 | + | |
| 411 | + <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" | |
| 412 | + width="110" | |
| 413 | + height="14" | |
| 414 | + class="clippy" | |
| 415 | + id="clippy" > | |
| 416 | + <param name="movie" value="https://assets2.github.com/flash/clippy.swf?v5"/> | |
| 417 | + <param name="allowScriptAccess" value="always" /> | |
| 418 | + <param name="quality" value="high" /> | |
| 419 | + <param name="scale" value="noscale" /> | |
| 420 | + <param NAME="FlashVars" value="id=clippy_4055&copied=copied!&copyto=copy to clipboard"> | |
| 421 | + <param name="bgcolor" value="#FFFFFF"> | |
| 422 | + <param name="wmode" value="opaque"> | |
| 423 | + <embed src="https://assets2.github.com/flash/clippy.swf?v5" | |
| 424 | + width="110" | |
| 425 | + height="14" | |
| 426 | + name="clippy" | |
| 427 | + quality="high" | |
| 428 | + allowScriptAccess="always" | |
| 429 | + type="application/x-shockwave-flash" | |
| 430 | + pluginspage="http://www.macromedia.com/go/getflashplayer" | |
| 431 | + FlashVars="id=clippy_4055&copied=copied!&copyto=copy to clipboard" | |
| 432 | + bgcolor="#FFFFFF" | |
| 433 | + wmode="opaque" | |
| 434 | + /> | |
| 435 | + </object> | |
| 436 | + | |
| 437 | + | |
| 438 | + </div> | |
| 439 | + | |
| 440 | + <div id="files"> | |
| 441 | + <div class="file"> | |
| 442 | + <div class="meta"> | |
| 443 | + <div class="info"> | |
| 444 | + <span class="icon"><img alt="Txt" height="16" src="https://assets3.github.com/images/icons/txt.png?6847bdee64e5b0e2ee04e4e961f33e28593984a2" width="16" /></span> | |
| 445 | + <span class="mode" title="File Mode">100644</span> | |
| 446 | + | |
| 447 | + <span>2.37 kb</span> | |
| 448 | + </div> | |
| 449 | + <ul class="actions"> | |
| 450 | + | |
| 451 | + <li><a href="/abraham/twitteroauth/raw/master/images/darker.png" id="raw-url">raw</a></li> | |
| 452 | + | |
| 453 | + <li><a href="/abraham/twitteroauth/commits/master/images/darker.png">history</a></li> | |
| 454 | + </ul> | |
| 455 | + </div> | |
| 456 | + | |
| 457 | + <div class="data type-text"> | |
| 458 | + | |
| 459 | + <div class="image"> | |
| 460 | + | |
| 461 | + | |
| 462 | + <img src="/abraham/twitteroauth/raw/master/images/darker.png" /> | |
| 463 | + | |
| 464 | + </div> | |
| 465 | + | |
| 466 | + </div> | |
| 467 | + | |
| 468 | + | |
| 469 | + </div> | |
| 470 | + </div> | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + </div> | |
| 475 | + | |
| 476 | + | |
| 477 | + </div> | |
| 478 | + | |
| 479 | + <div id="footer" class="clearfix"> | |
| 480 | + <div class="site"> | |
| 481 | + <div class="sponsor"> | |
| 482 | + <a href="http://www.rackspace.com" class="logo"> | |
| 483 | + <img alt="Dedicated Server" src="https://assets0.github.com/images/modules/footer/rackspace_logo.png?v2?6847bdee64e5b0e2ee04e4e961f33e28593984a2" /> | |
| 484 | + </a> | |
| 485 | + Powered by the <a href="http://www.rackspace.com ">Dedicated | |
| 486 | + Servers</a> and<br/> <a href="http://www.rackspacecloud.com">Cloud | |
| 487 | + Computing</a> of Rackspace Hosting<span>®</span> | |
| 488 | + </div> | |
| 489 | + | |
| 490 | + <ul class="links"> | |
| 491 | + <li class="blog"><a href="https://github.com/blog">Blog</a></li> | |
| 492 | + <li><a href="http://support.github.com">Support</a></li> | |
| 493 | + <li><a href="https://github.com/training">Training</a></li> | |
| 494 | + <li><a href="http://jobs.github.com">Job Board</a></li> | |
| 495 | + <li><a href="http://shop.github.com">Shop</a></li> | |
| 496 | + <li><a href="https://github.com/contact">Contact</a></li> | |
| 497 | + <li><a href="http://develop.github.com">API</a></li> | |
| 498 | + <li><a href="http://status.github.com">Status</a></li> | |
| 499 | + </ul> | |
| 500 | + <ul class="sosueme"> | |
| 501 | + <li class="main">© 2010 <span id="_rrt" title="0.19761s from fe5.rs.github.com">GitHub</span> Inc. All rights reserved.</li> | |
| 502 | + <li><a href="/site/terms">Terms of Service</a></li> | |
| 503 | + <li><a href="/site/privacy">Privacy</a></li> | |
| 504 | + <li><a href="https://github.com/security">Security</a></li> | |
| 505 | + </ul> | |
| 506 | + </div> | |
| 507 | + </div><!-- /#footer --> | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + <!-- current locale: --> | |
| 513 | + <div class="locales"> | |
| 514 | + <div class="site"> | |
| 515 | + | |
| 516 | + <ul class="choices clearfix limited-locales"> | |
| 517 | + <li><span class="current">English</span></li> | |
| 518 | + | |
| 519 | + <li><a rel="nofollow" href="?locale=de">Deutsch</a></li> | |
| 520 | + | |
| 521 | + <li><a rel="nofollow" href="?locale=fr">Français</a></li> | |
| 522 | + | |
| 523 | + <li><a rel="nofollow" href="?locale=ja">日本語</a></li> | |
| 524 | + | |
| 525 | + <li><a rel="nofollow" href="?locale=pt-BR">Português (BR)</a></li> | |
| 526 | + | |
| 527 | + <li><a rel="nofollow" href="?locale=ru">Русский</a></li> | |
| 528 | + | |
| 529 | + <li><a rel="nofollow" href="?locale=zh">中文</a></li> | |
| 530 | + | |
| 531 | + <li class="all"><a href="#" class="minibutton btn-forward js-all-locales"><span><span class="icon"></span>See all available languages</span></a></li> | |
| 532 | + </ul> | |
| 533 | + | |
| 534 | + <div class="all-locales clearfix"> | |
| 535 | + <h3>Your current locale selection: <strong>English</strong>. Choose another?</h3> | |
| 536 | + | |
| 537 | + | |
| 538 | + <ul class="choices"> | |
| 539 | + | |
| 540 | + <li><a rel="nofollow" href="?locale=en">English</a></li> | |
| 541 | + | |
| 542 | + <li><a rel="nofollow" href="?locale=af">Afrikaans</a></li> | |
| 543 | + | |
| 544 | + <li><a rel="nofollow" href="?locale=ca">Català</a></li> | |
| 545 | + | |
| 546 | + <li><a rel="nofollow" href="?locale=cs">Čeština</a></li> | |
| 547 | + | |
| 548 | + </ul> | |
| 549 | + | |
| 550 | + <ul class="choices"> | |
| 551 | + | |
| 552 | + <li><a rel="nofollow" href="?locale=de">Deutsch</a></li> | |
| 553 | + | |
| 554 | + <li><a rel="nofollow" href="?locale=es">Español</a></li> | |
| 555 | + | |
| 556 | + <li><a rel="nofollow" href="?locale=fr">Français</a></li> | |
| 557 | + | |
| 558 | + <li><a rel="nofollow" href="?locale=hr">Hrvatski</a></li> | |
| 559 | + | |
| 560 | + </ul> | |
| 561 | + | |
| 562 | + <ul class="choices"> | |
| 563 | + | |
| 564 | + <li><a rel="nofollow" href="?locale=id">Indonesia</a></li> | |
| 565 | + | |
| 566 | + <li><a rel="nofollow" href="?locale=it">Italiano</a></li> | |
| 567 | + | |
| 568 | + <li><a rel="nofollow" href="?locale=ja">日本語</a></li> | |
| 569 | + | |
| 570 | + <li><a rel="nofollow" href="?locale=nl">Nederlands</a></li> | |
| 571 | + | |
| 572 | + </ul> | |
| 573 | + | |
| 574 | + <ul class="choices"> | |
| 575 | + | |
| 576 | + <li><a rel="nofollow" href="?locale=no">Norsk</a></li> | |
| 577 | + | |
| 578 | + <li><a rel="nofollow" href="?locale=pl">Polski</a></li> | |
| 579 | + | |
| 580 | + <li><a rel="nofollow" href="?locale=pt-BR">Português (BR)</a></li> | |
| 581 | + | |
| 582 | + <li><a rel="nofollow" href="?locale=ru">Русский</a></li> | |
| 583 | + | |
| 584 | + </ul> | |
| 585 | + | |
| 586 | + <ul class="choices"> | |
| 587 | + | |
| 588 | + <li><a rel="nofollow" href="?locale=sr">Српски</a></li> | |
| 589 | + | |
| 590 | + <li><a rel="nofollow" href="?locale=sv">Svenska</a></li> | |
| 591 | + | |
| 592 | + <li><a rel="nofollow" href="?locale=zh">中文</a></li> | |
| 593 | + | |
| 594 | + </ul> | |
| 595 | + | |
| 596 | + </div> | |
| 597 | + | |
| 598 | + </div> | |
| 599 | + <div class="fade"></div> | |
| 600 | + </div> | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + <script>window._auth_token = "0788e12631f37df2bd75592390a297816b6698da"</script> | |
| 605 | + <div id="keyboard_shortcuts_pane" style="display:none"> | |
| 606 | + <h2>Keyboard Shortcuts</h2> | |
| 607 | + | |
| 608 | + <div class="columns threecols"> | |
| 609 | + <div class="column first"> | |
| 610 | + <h3>Site wide shortcuts</h3> | |
| 611 | + <dl class="keyboard-mappings"> | |
| 612 | + <dt>s</dt> | |
| 613 | + <dd>Focus site search</dd> | |
| 614 | + </dl> | |
| 615 | + <dl class="keyboard-mappings"> | |
| 616 | + <dt>?</dt> | |
| 617 | + <dd>Bring up this help dialog</dd> | |
| 618 | + </dl> | |
| 619 | + </div><!-- /.column.first --> | |
| 620 | + <div class="column middle"> | |
| 621 | + <h3>Commit list</h3> | |
| 622 | + <dl class="keyboard-mappings"> | |
| 623 | + <dt>j</dt> | |
| 624 | + <dd>Move selected down</dd> | |
| 625 | + </dl> | |
| 626 | + <dl class="keyboard-mappings"> | |
| 627 | + <dt>k</dt> | |
| 628 | + <dd>Move selected up</dd> | |
| 629 | + </dl> | |
| 630 | + <dl class="keyboard-mappings"> | |
| 631 | + <dt>t</dt> | |
| 632 | + <dd>Open tree</dd> | |
| 633 | + </dl> | |
| 634 | + <dl class="keyboard-mappings"> | |
| 635 | + <dt>p</dt> | |
| 636 | + <dd>Open parent</dd> | |
| 637 | + </dl> | |
| 638 | + <dl class="keyboard-mappings"> | |
| 639 | + <dt>c <em>or</em> o <em>or</em> enter</dt> | |
| 640 | + <dd>Open commit</dd> | |
| 641 | + </dl> | |
| 642 | + </div><!-- /.column.first --> | |
| 643 | + <div class="column last"> | |
| 644 | + <h3>Pull request list</h3> | |
| 645 | + <dl class="keyboard-mappings"> | |
| 646 | + <dt>j</dt> | |
| 647 | + <dd>Move selected down</dd> | |
| 648 | + </dl> | |
| 649 | + <dl class="keyboard-mappings"> | |
| 650 | + <dt>k</dt> | |
| 651 | + <dd>Move selected up</dd> | |
| 652 | + </dl> | |
| 653 | + <dl class="keyboard-mappings"> | |
| 654 | + <dt>o <em>or</em> enter</dt> | |
| 655 | + <dd>Open issue</dd> | |
| 656 | + </dl> | |
| 657 | + </div><!-- /.columns.last --> | |
| 658 | + </div><!-- /.columns.equacols --> | |
| 659 | + | |
| 660 | + <div class="rule"></div> | |
| 661 | + | |
| 662 | + <h3>Issues</h3> | |
| 663 | + | |
| 664 | + <div class="columns threecols"> | |
| 665 | + <div class="column first"> | |
| 666 | + <dl class="keyboard-mappings"> | |
| 667 | + <dt>j</dt> | |
| 668 | + <dd>Move selected down</dd> | |
| 669 | + </dl> | |
| 670 | + <dl class="keyboard-mappings"> | |
| 671 | + <dt>k</dt> | |
| 672 | + <dd>Move selected up</dd> | |
| 673 | + </dl> | |
| 674 | + <dl class="keyboard-mappings"> | |
| 675 | + <dt>x</dt> | |
| 676 | + <dd>Toggle select target</dd> | |
| 677 | + </dl> | |
| 678 | + <dl class="keyboard-mappings"> | |
| 679 | + <dt>o <em>or</em> enter</dt> | |
| 680 | + <dd>Open issue</dd> | |
| 681 | + </dl> | |
| 682 | + </div><!-- /.column.first --> | |
| 683 | + <div class="column middle"> | |
| 684 | + <dl class="keyboard-mappings"> | |
| 685 | + <dt>I</dt> | |
| 686 | + <dd>Mark selected as read</dd> | |
| 687 | + </dl> | |
| 688 | + <dl class="keyboard-mappings"> | |
| 689 | + <dt>U</dt> | |
| 690 | + <dd>Mark selected as unread</dd> | |
| 691 | + </dl> | |
| 692 | + <dl class="keyboard-mappings"> | |
| 693 | + <dt>e</dt> | |
| 694 | + <dd>Close selected</dd> | |
| 695 | + </dl> | |
| 696 | + <dl class="keyboard-mappings"> | |
| 697 | + <dt>y</dt> | |
| 698 | + <dd>Remove selected from view</dd> | |
| 699 | + </dl> | |
| 700 | + </div><!-- /.column.middle --> | |
| 701 | + <div class="column last"> | |
| 702 | + <dl class="keyboard-mappings"> | |
| 703 | + <dt>c</dt> | |
| 704 | + <dd>Create issue</dd> | |
| 705 | + </dl> | |
| 706 | + <dl class="keyboard-mappings"> | |
| 707 | + <dt>l</dt> | |
| 708 | + <dd>Create label</dd> | |
| 709 | + </dl> | |
| 710 | + <dl class="keyboard-mappings"> | |
| 711 | + <dt>i</dt> | |
| 712 | + <dd>Back to inbox</dd> | |
| 713 | + </dl> | |
| 714 | + <dl class="keyboard-mappings"> | |
| 715 | + <dt>u</dt> | |
| 716 | + <dd>Back to issues</dd> | |
| 717 | + </dl> | |
| 718 | + <dl class="keyboard-mappings"> | |
| 719 | + <dt>/</dt> | |
| 720 | + <dd>Focus issues search</dd> | |
| 721 | + </dl> | |
| 722 | + </div> | |
| 723 | + </div> | |
| 724 | + | |
| 725 | + <div class="rule"></div> | |
| 726 | + | |
| 727 | + <h3>Network Graph</h3> | |
| 728 | + <div class="columns equacols"> | |
| 729 | + <div class="column first"> | |
| 730 | + <dl class="keyboard-mappings"> | |
| 731 | + <dt>← <em>or</em> h</dt> | |
| 732 | + <dd>Scroll left</dd> | |
| 733 | + </dl> | |
| 734 | + <dl class="keyboard-mappings"> | |
| 735 | + <dt>→ <em>or</em> l</dt> | |
| 736 | + <dd>Scroll right</dd> | |
| 737 | + </dl> | |
| 738 | + <dl class="keyboard-mappings"> | |
| 739 | + <dt>↑ <em>or</em> k</dt> | |
| 740 | + <dd>Scroll up</dd> | |
| 741 | + </dl> | |
| 742 | + <dl class="keyboard-mappings"> | |
| 743 | + <dt>↓ <em>or</em> j</dt> | |
| 744 | + <dd>Scroll down</dd> | |
| 745 | + </dl> | |
| 746 | + <dl class="keyboard-mappings"> | |
| 747 | + <dt>t</dt> | |
| 748 | + <dd>Toggle visibility of head labels</dd> | |
| 749 | + </dl> | |
| 750 | + </div><!-- /.column.first --> | |
| 751 | + <div class="column last"> | |
| 752 | + <dl class="keyboard-mappings"> | |
| 753 | + <dt>shift ← <em>or</em> shift h</dt> | |
| 754 | + <dd>Scroll all the way left</dd> | |
| 755 | + </dl> | |
| 756 | + <dl class="keyboard-mappings"> | |
| 757 | + <dt>shift → <em>or</em> shift l</dt> | |
| 758 | + <dd>Scroll all the way right</dd> | |
| 759 | + </dl> | |
| 760 | + <dl class="keyboard-mappings"> | |
| 761 | + <dt>shift ↑ <em>or</em> shift k</dt> | |
| 762 | + <dd>Scroll all the way up</dd> | |
| 763 | + </dl> | |
| 764 | + <dl class="keyboard-mappings"> | |
| 765 | + <dt>shift ↓ <em>or</em> shift j</dt> | |
| 766 | + <dd>Scroll all the way down</dd> | |
| 767 | + </dl> | |
| 768 | + </div><!-- /.column.last --> | |
| 769 | + </div> | |
| 770 | + | |
| 771 | +</div> | |
| 772 | + | |
| 773 | + | |
| 774 | + <!--[if IE 8]> | |
| 775 | + <script type="text/javascript" charset="utf-8"> | |
| 776 | + $(document.body).addClass("ie8") | |
| 777 | + </script> | |
| 778 | + <![endif]--> | |
| 779 | + | |
| 780 | + <!--[if IE 7]> | |
| 781 | + <script type="text/javascript" charset="utf-8"> | |
| 782 | + $(document.body).addClass("ie7") | |
| 783 | + </script> | |
| 784 | + <![endif]--> | |
| 785 | + | |
| 786 | + <script type="text/javascript"> | |
| 787 | + _kmq.push(['trackClick', 'entice-signup-button', 'Entice banner clicked']); | |
| 788 | + | |
| 789 | + </script> | |
| 790 | + | |
| 791 | + </body> | |
| 792 | +</html> | |
| 793 | + | ... | ... |
| ... | ... | @@ -0,0 +1,793 @@ |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
| 7 | + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
| 8 | + | |
| 9 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |
| 10 | + <head> | |
| 11 | + <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> | |
| 12 | + <meta http-equiv="X-UA-Compatible" content="chrome=1"> | |
| 13 | + <title>images/lighter.png at master from abraham's twitteroauth - GitHub</title> | |
| 14 | + <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub" /> | |
| 15 | + <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub" /> | |
| 16 | + | |
| 17 | + <link href="https://assets1.github.com/stylesheets/bundle_common.css?6847bdee64e5b0e2ee04e4e961f33e28593984a2" media="screen" rel="stylesheet" type="text/css" /> | |
| 18 | +<link href="https://assets0.github.com/stylesheets/bundle_github.css?6847bdee64e5b0e2ee04e4e961f33e28593984a2" media="screen" rel="stylesheet" type="text/css" /> | |
| 19 | + | |
| 20 | + <script type="text/javascript" charset="utf-8"> | |
| 21 | + var GitHub = {} | |
| 22 | + var github_user = null | |
| 23 | + | |
| 24 | + </script> | |
| 25 | + <script src="https://assets2.github.com/javascripts/jquery/jquery-1.4.2.min.js?6847bdee64e5b0e2ee04e4e961f33e28593984a2" type="text/javascript"></script> | |
| 26 | + <script src="https://assets3.github.com/javascripts/bundle_common.js?6847bdee64e5b0e2ee04e4e961f33e28593984a2" type="text/javascript"></script> | |
| 27 | +<script src="https://assets3.github.com/javascripts/bundle_github.js?6847bdee64e5b0e2ee04e4e961f33e28593984a2" type="text/javascript"></script> | |
| 28 | + | |
| 29 | + <script type="text/javascript" charset="utf-8"> | |
| 30 | + GitHub.spy({ | |
| 31 | + repo: "abraham/twitteroauth" | |
| 32 | + }) | |
| 33 | + </script> | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + <link href="https://github.com/abraham/twitteroauth/commits/master.atom" rel="alternate" title="Recent Commits to twitteroauth:master" type="application/atom+xml" /> | |
| 41 | + | |
| 42 | + <meta name="description" content="The first PHP Library to support OAuth for Twitter's REST API." /> | |
| 43 | + <script type="text/javascript"> | |
| 44 | + GitHub.nameWithOwner = GitHub.nameWithOwner || "abraham/twitteroauth"; | |
| 45 | + GitHub.currentRef = 'master'; | |
| 46 | + </script> | |
| 47 | + | |
| 48 | + | |
| 49 | + <script type="text/javascript"> | |
| 50 | + var _gaq = _gaq || []; | |
| 51 | + _gaq.push(['_setAccount', 'UA-3769691-2']); | |
| 52 | + _gaq.push(['_trackPageview']); | |
| 53 | + (function() { | |
| 54 | + var ga = document.createElement('script'); | |
| 55 | + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | |
| 56 | + ga.setAttribute('async', 'true'); | |
| 57 | + document.documentElement.firstChild.appendChild(ga); | |
| 58 | + })(); | |
| 59 | + </script> | |
| 60 | + | |
| 61 | + </head> | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + <body class="logged_out "> | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + <script type="text/javascript"> | |
| 70 | + var _kmq = _kmq || []; | |
| 71 | + function _kms(u){ | |
| 72 | + var s = document.createElement('script'); var f = document.getElementsByTagName('script')[0]; s.type = 'text/javascript'; s.async = true; | |
| 73 | + s.src = u; f.parentNode.insertBefore(s, f); | |
| 74 | + } | |
| 75 | + _kms('//i.kissmetrics.com/i.js');_kms('//doug1izaerwt3.cloudfront.net/406e8bf3a2b8846ead55afb3cfaf6664523e3a54.1.js'); | |
| 76 | + </script> | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + <div class="subnavd" id="main"> | |
| 86 | + <div id="header" class="true"> | |
| 87 | + | |
| 88 | + <a class="logo boring" href="https://github.com"> | |
| 89 | + <img src="/images/modules/header/logov3.png?changed" class="default" alt="github" /> | |
| 90 | + <![if !IE]> | |
| 91 | + <img src="/images/modules/header/logov3-hover.png" class="hover" alt="github" /> | |
| 92 | + <![endif]> | |
| 93 | + </a> | |
| 94 | + | |
| 95 | + | |
| 96 | + <div class="topsearch"> | |
| 97 | + | |
| 98 | + <ul class="nav logged_out"> | |
| 99 | + <li><a href="https://github.com">Home</a></li> | |
| 100 | + <li class="pricing"><a href="/plans">Pricing and Signup</a></li> | |
| 101 | + <li><a href="https://github.com/training">Training</a></li> | |
| 102 | + <li><a href="https://gist.github.com">Gist</a></li> | |
| 103 | + <li><a href="/blog">Blog</a></li> | |
| 104 | + <li><a href="https://github.com/login">Login</a></li> | |
| 105 | + </ul> | |
| 106 | + | |
| 107 | +</div> | |
| 108 | + | |
| 109 | + </div> | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + <div class="site"> | |
| 115 | + <div class="pagehead repohead vis-public "> | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + <div class="title-actions-bar"> | |
| 120 | + <h1> | |
| 121 | + <a href="/abraham">abraham</a> / <strong><a href="https://github.com/abraham/twitteroauth">twitteroauth</a></strong> | |
| 122 | + | |
| 123 | + | |
| 124 | + </h1> | |
| 125 | + | |
| 126 | + | |
| 127 | + <ul class="actions"> | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + <li class="for-owner" style="display:none"><a href="https://github.com/abraham/twitteroauth/admin" class="minibutton btn-admin "><span><span class="icon"></span>Admin</span></a></li> | |
| 132 | + <li> | |
| 133 | + <a href="/abraham/twitteroauth/toggle_watch" class="minibutton btn-watch " id="watch_button" onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '0788e12631f37df2bd75592390a297816b6698da'); f.appendChild(s);f.submit();return false;" style="display:none"><span><span class="icon"></span>Watch</span></a> | |
| 134 | + <a href="/abraham/twitteroauth/toggle_watch" class="minibutton btn-watch " id="unwatch_button" onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '0788e12631f37df2bd75592390a297816b6698da'); f.appendChild(s);f.submit();return false;" style="display:none"><span><span class="icon"></span>Unwatch</span></a> | |
| 135 | + </li> | |
| 136 | + | |
| 137 | + | |
| 138 | + <li class="for-notforked" style="display:none"><a href="/abraham/twitteroauth/fork" class="minibutton btn-fork " id="fork_button" onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '0788e12631f37df2bd75592390a297816b6698da'); f.appendChild(s);f.submit();return false;"><span><span class="icon"></span>Fork</span></a></li> | |
| 139 | + <li class="for-hasfork" style="display:none"><a href="#" class="minibutton btn-fork " id="your_fork_button"><span><span class="icon"></span>Your Fork</span></a></li> | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + <li class="repostats"> | |
| 147 | + <ul class="repo-stats"> | |
| 148 | + <li class="watchers"><a href="/abraham/twitteroauth/watchers" title="Watchers" class="tooltipped downwards">591</a></li> | |
| 149 | + <li class="forks"><a href="/abraham/twitteroauth/network" title="Forks" class="tooltipped downwards">79</a></li> | |
| 150 | + </ul> | |
| 151 | + </li> | |
| 152 | + </ul> | |
| 153 | + | |
| 154 | + </div> | |
| 155 | + | |
| 156 | + | |
| 157 | + <ul class="tabs"> | |
| 158 | + <li><a href="https://github.com/abraham/twitteroauth/tree/master" class="selected" highlight="repo_source">Source</a></li> | |
| 159 | + <li><a href="https://github.com/abraham/twitteroauth/commits/master" highlight="repo_commits">Commits</a></li> | |
| 160 | + <li><a href="/abraham/twitteroauth/network" highlight="repo_network">Network</a></li> | |
| 161 | + <li><a href="/abraham/twitteroauth/pulls" highlight="repo_pulls">Pull Requests (4)</a></li> | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + <li><a href="/abraham/twitteroauth/issues" highlight="issues">Issues (34)</a></li> | |
| 168 | + | |
| 169 | + | |
| 170 | + <li><a href="/abraham/twitteroauth/wiki" highlight="repo_wiki">Wiki (3)</a></li> | |
| 171 | + | |
| 172 | + <li><a href="/abraham/twitteroauth/graphs" highlight="repo_graphs">Graphs</a></li> | |
| 173 | + | |
| 174 | + <li class="contextswitch nochoices"> | |
| 175 | + <span class="toggle leftwards" > | |
| 176 | + <em>Branch:</em> | |
| 177 | + <code>master</code> | |
| 178 | + </span> | |
| 179 | + </li> | |
| 180 | + </ul> | |
| 181 | + | |
| 182 | + <div style="display:none" id="pl-description"><p><em class="placeholder">click here to add a description</em></p></div> | |
| 183 | + <div style="display:none" id="pl-homepage"><p><em class="placeholder">click here to add a homepage</em></p></div> | |
| 184 | + | |
| 185 | + <div class="subnav-bar"> | |
| 186 | + | |
| 187 | + <ul> | |
| 188 | + <li> | |
| 189 | + <a href="#" class="dropdown">Switch Branches (3)</a> | |
| 190 | + <ul> | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + <li><a href="/abraham/twitteroauth/blob/0.2.0/images/lighter.png" action="show">0.2.0</a></li> | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + <li><a href="/abraham/twitteroauth/blob/gh-pages/images/lighter.png" action="show">gh-pages</a></li> | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + <li><strong>master ✓</strong></li> | |
| 204 | + | |
| 205 | + </ul> | |
| 206 | + </li> | |
| 207 | + <li> | |
| 208 | + <a href="#" class="dropdown ">Switch Tags (5)</a> | |
| 209 | + <ul> | |
| 210 | + | |
| 211 | + <li><a href="/abraham/twitteroauth/blob/0.2.0-beta3/images/lighter.png">0.2.0-beta3</a></li> | |
| 212 | + | |
| 213 | + | |
| 214 | + <li><a href="/abraham/twitteroauth/blob/0.2.0-beta2/images/lighter.png">0.2.0-beta2</a></li> | |
| 215 | + | |
| 216 | + | |
| 217 | + <li><a href="/abraham/twitteroauth/blob/0.2.0-beta/images/lighter.png">0.2.0-beta</a></li> | |
| 218 | + | |
| 219 | + | |
| 220 | + <li><a href="/abraham/twitteroauth/blob/0.1.1/images/lighter.png">0.1.1</a></li> | |
| 221 | + | |
| 222 | + | |
| 223 | + <li><a href="/abraham/twitteroauth/blob/0.1.0/images/lighter.png">0.1.0</a></li> | |
| 224 | + | |
| 225 | + </ul> | |
| 226 | + | |
| 227 | + </li> | |
| 228 | + <li> | |
| 229 | + | |
| 230 | + <a href="/abraham/twitteroauth/branches" class="manage">Branch List</a> | |
| 231 | + | |
| 232 | + </li> | |
| 233 | + </ul> | |
| 234 | +</div> | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + <div id="repo_details" class="metabox clearfix"> | |
| 247 | + <div id="repo_details_loader" class="metabox-loader" style="display:none">Sending Request…</div> | |
| 248 | + | |
| 249 | + <a href="/abraham/twitteroauth/downloads" class="download-source" id="download_button" title="Download source, tagged packages and binaries."><span class="icon"></span>Downloads</a> | |
| 250 | + | |
| 251 | + <div id="repository_desc_wrapper"> | |
| 252 | + <div id="repository_description" rel="repository_description_edit"> | |
| 253 | + | |
| 254 | + <p>The first PHP Library to support OAuth for Twitter's REST API. | |
| 255 | + <span id="read_more" style="display:none">— <a href="#readme">Read more</a></span> | |
| 256 | + </p> | |
| 257 | + | |
| 258 | + </div> | |
| 259 | + | |
| 260 | + <div id="repository_description_edit" style="display:none;" class="inline-edit"> | |
| 261 | + <form action="/abraham/twitteroauth/admin/update" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="0788e12631f37df2bd75592390a297816b6698da" /></div> | |
| 262 | + <input type="hidden" name="field" value="repository_description"> | |
| 263 | + <input type="text" class="textfield" name="value" value="The first PHP Library to support OAuth for Twitter's REST API."> | |
| 264 | + <div class="form-actions"> | |
| 265 | + <button class="minibutton"><span>Save</span></button> <a href="#" class="cancel">Cancel</a> | |
| 266 | + </div> | |
| 267 | + </form> | |
| 268 | + </div> | |
| 269 | + | |
| 270 | + | |
| 271 | + <div class="repository-homepage" id="repository_homepage" rel="repository_homepage_edit"> | |
| 272 | + <p><a href="http://twitteroauth.labs.poseurtech.com" rel="nofollow">http://twitteroauth.labs.poseurtech.com</a></p> | |
| 273 | + </div> | |
| 274 | + | |
| 275 | + <div id="repository_homepage_edit" style="display:none;" class="inline-edit"> | |
| 276 | + <form action="/abraham/twitteroauth/admin/update" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="0788e12631f37df2bd75592390a297816b6698da" /></div> | |
| 277 | + <input type="hidden" name="field" value="repository_homepage"> | |
| 278 | + <input type="text" class="textfield" name="value" value="http://twitteroauth.labs.poseurtech.com"> | |
| 279 | + <div class="form-actions"> | |
| 280 | + <button class="minibutton"><span>Save</span></button> <a href="#" class="cancel">Cancel</a> | |
| 281 | + </div> | |
| 282 | + </form> | |
| 283 | + </div> | |
| 284 | + </div> | |
| 285 | + <div class="rule "></div> | |
| 286 | + <div id="url_box" class="url-box"> | |
| 287 | + <ul class="clone-urls"> | |
| 288 | + | |
| 289 | + | |
| 290 | + <li id="http_clone_url"><a href="https://github.com/abraham/twitteroauth.git" data-permissions="Read-Only">HTTP</a></li> | |
| 291 | + <li id="public_clone_url"><a href="git://github.com/abraham/twitteroauth.git" data-permissions="Read-Only">Git Read-Only</a></li> | |
| 292 | + | |
| 293 | + | |
| 294 | + </ul> | |
| 295 | + <input type="text" spellcheck="false" id="url_field" class="url-field" /> | |
| 296 | + <span style="display:none" id="url_box_clippy"></span> | |
| 297 | + <span id="clippy_tooltip_url_box_clippy" class="clippy-tooltip tooltipped" title="copy to clipboard"> | |
| 298 | + <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" | |
| 299 | + width="14" | |
| 300 | + height="14" | |
| 301 | + class="clippy" | |
| 302 | + id="clippy" > | |
| 303 | + <param name="movie" value="https://assets2.github.com/flash/clippy.swf?v5"/> | |
| 304 | + <param name="allowScriptAccess" value="always" /> | |
| 305 | + <param name="quality" value="high" /> | |
| 306 | + <param name="scale" value="noscale" /> | |
| 307 | + <param NAME="FlashVars" value="id=url_box_clippy&copied=&copyto="> | |
| 308 | + <param name="bgcolor" value="#FFFFFF"> | |
| 309 | + <param name="wmode" value="opaque"> | |
| 310 | + <embed src="https://assets2.github.com/flash/clippy.swf?v5" | |
| 311 | + width="14" | |
| 312 | + height="14" | |
| 313 | + name="clippy" | |
| 314 | + quality="high" | |
| 315 | + allowScriptAccess="always" | |
| 316 | + type="application/x-shockwave-flash" | |
| 317 | + pluginspage="http://www.macromedia.com/go/getflashplayer" | |
| 318 | + FlashVars="id=url_box_clippy&copied=&copyto=" | |
| 319 | + bgcolor="#FFFFFF" | |
| 320 | + wmode="opaque" | |
| 321 | + /> | |
| 322 | + </object> | |
| 323 | + </span> | |
| 324 | + | |
| 325 | + <p id="url_description">This URL has <strong>Read+Write</strong> access</p> | |
| 326 | + </div> | |
| 327 | + </div> | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + </div><!-- /.pagehead --> | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | +<script type="text/javascript"> | |
| 345 | + GitHub.currentCommitRef = 'master' | |
| 346 | + GitHub.currentRepoOwner = 'abraham' | |
| 347 | + GitHub.currentRepo = "twitteroauth" | |
| 348 | + GitHub.downloadRepo = '/abraham/twitteroauth/archives/master' | |
| 349 | + GitHub.revType = "master" | |
| 350 | + | |
| 351 | + GitHub.controllerName = "blob" | |
| 352 | + GitHub.actionName = "show" | |
| 353 | + GitHub.currentAction = "blob#show" | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | +</script> | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + <div id="commit"> | |
| 368 | + <div class="group"> | |
| 369 | + | |
| 370 | + <div class="envelope commit"> | |
| 371 | + <div class="human"> | |
| 372 | + | |
| 373 | + <div class="message"><pre><a href="/abraham/twitteroauth/commit/76446fa719466c09b20fe021bf9e92f54afc43e1">Added getXAuthToken method, updated documentation and fixed some spelling issues.</a> </pre></div> | |
| 374 | + | |
| 375 | + | |
| 376 | + <div class="actor"> | |
| 377 | + <div class="gravatar"> | |
| 378 | + | |
| 379 | + <img src="https://secure.gravatar.com/avatar/cfc268557922ae6f5464a8cb337ceac2?s=140&d=https%3A%2F%2Fgithub.com%2Fimages%2Fgravatars%2Fgravatar-140.png" alt="" width="30" height="30" /> | |
| 380 | + </div> | |
| 381 | + <div class="name"><a href="/abraham">abraham</a> <span>(author)</span></div> | |
| 382 | + <div class="date"> | |
| 383 | + <abbr class="relatize" title="2010-03-10 18:51:58">Wed Mar 10 18:51:58 -0800 2010</abbr> | |
| 384 | + </div> | |
| 385 | + </div> | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + </div> | |
| 390 | + <div class="machine"> | |
| 391 | + <span>c</span>ommit <a href="/abraham/twitteroauth/commit/76446fa719466c09b20fe021bf9e92f54afc43e1" hotkey="c">76446fa719466c09b20f</a><br /> | |
| 392 | + <span>t</span>ree <a href="/abraham/twitteroauth/tree/76446fa719466c09b20fe021bf9e92f54afc43e1" hotkey="t">140d535db90866cac2a7</a><br /> | |
| 393 | + | |
| 394 | + <span>p</span>arent | |
| 395 | + | |
| 396 | + <a href="/abraham/twitteroauth/tree/8da02a678b9c408eb8ca1ffd9c38323f2da632a5" hotkey="p">8da02a678b9c408eb8ca</a> | |
| 397 | + | |
| 398 | + | |
| 399 | + </div> | |
| 400 | + </div> | |
| 401 | + | |
| 402 | + </div> | |
| 403 | + </div> | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + <div id="path"> | |
| 409 | + <b><a href="/abraham/twitteroauth/tree/master">twitteroauth</a></b> / <a href="/abraham/twitteroauth/tree/master/images">images</a> / lighter.png <span style="display:none" id="clippy_1778">images/lighter.png</span> | |
| 410 | + | |
| 411 | + <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" | |
| 412 | + width="110" | |
| 413 | + height="14" | |
| 414 | + class="clippy" | |
| 415 | + id="clippy" > | |
| 416 | + <param name="movie" value="https://assets1.github.com/flash/clippy.swf?v5"/> | |
| 417 | + <param name="allowScriptAccess" value="always" /> | |
| 418 | + <param name="quality" value="high" /> | |
| 419 | + <param name="scale" value="noscale" /> | |
| 420 | + <param NAME="FlashVars" value="id=clippy_1778&copied=copied!&copyto=copy to clipboard"> | |
| 421 | + <param name="bgcolor" value="#FFFFFF"> | |
| 422 | + <param name="wmode" value="opaque"> | |
| 423 | + <embed src="https://assets1.github.com/flash/clippy.swf?v5" | |
| 424 | + width="110" | |
| 425 | + height="14" | |
| 426 | + name="clippy" | |
| 427 | + quality="high" | |
| 428 | + allowScriptAccess="always" | |
| 429 | + type="application/x-shockwave-flash" | |
| 430 | + pluginspage="http://www.macromedia.com/go/getflashplayer" | |
| 431 | + FlashVars="id=clippy_1778&copied=copied!&copyto=copy to clipboard" | |
| 432 | + bgcolor="#FFFFFF" | |
| 433 | + wmode="opaque" | |
| 434 | + /> | |
| 435 | + </object> | |
| 436 | + | |
| 437 | + | |
| 438 | + </div> | |
| 439 | + | |
| 440 | + <div id="files"> | |
| 441 | + <div class="file"> | |
| 442 | + <div class="meta"> | |
| 443 | + <div class="info"> | |
| 444 | + <span class="icon"><img alt="Txt" height="16" src="https://assets2.github.com/images/icons/txt.png?bd5b57138194d8b178fd949e16173262d8b89778" width="16" /></span> | |
| 445 | + <span class="mode" title="File Mode">100644</span> | |
| 446 | + | |
| 447 | + <span>2.49 kb</span> | |
| 448 | + </div> | |
| 449 | + <ul class="actions"> | |
| 450 | + | |
| 451 | + <li><a href="/abraham/twitteroauth/raw/master/images/lighter.png" id="raw-url">raw</a></li> | |
| 452 | + | |
| 453 | + <li><a href="/abraham/twitteroauth/commits/master/images/lighter.png">history</a></li> | |
| 454 | + </ul> | |
| 455 | + </div> | |
| 456 | + | |
| 457 | + <div class="data type-text"> | |
| 458 | + | |
| 459 | + <div class="image"> | |
| 460 | + | |
| 461 | + | |
| 462 | + <img src="/abraham/twitteroauth/raw/master/images/lighter.png" /> | |
| 463 | + | |
| 464 | + </div> | |
| 465 | + | |
| 466 | + </div> | |
| 467 | + | |
| 468 | + | |
| 469 | + </div> | |
| 470 | + </div> | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + </div> | |
| 475 | + | |
| 476 | + | |
| 477 | + </div> | |
| 478 | + | |
| 479 | + <div id="footer" class="clearfix"> | |
| 480 | + <div class="site"> | |
| 481 | + <div class="sponsor"> | |
| 482 | + <a href="http://www.rackspace.com" class="logo"> | |
| 483 | + <img alt="Dedicated Server" src="https://assets0.github.com/images/modules/footer/rackspace_logo.png?v2?6847bdee64e5b0e2ee04e4e961f33e28593984a2" /> | |
| 484 | + </a> | |
| 485 | + Powered by the <a href="http://www.rackspace.com ">Dedicated | |
| 486 | + Servers</a> and<br/> <a href="http://www.rackspacecloud.com">Cloud | |
| 487 | + Computing</a> of Rackspace Hosting<span>®</span> | |
| 488 | + </div> | |
| 489 | + | |
| 490 | + <ul class="links"> | |
| 491 | + <li class="blog"><a href="https://github.com/blog">Blog</a></li> | |
| 492 | + <li><a href="http://support.github.com">Support</a></li> | |
| 493 | + <li><a href="https://github.com/training">Training</a></li> | |
| 494 | + <li><a href="http://jobs.github.com">Job Board</a></li> | |
| 495 | + <li><a href="http://shop.github.com">Shop</a></li> | |
| 496 | + <li><a href="https://github.com/contact">Contact</a></li> | |
| 497 | + <li><a href="http://develop.github.com">API</a></li> | |
| 498 | + <li><a href="http://status.github.com">Status</a></li> | |
| 499 | + </ul> | |
| 500 | + <ul class="sosueme"> | |
| 501 | + <li class="main">© 2010 <span id="_rrt" title="0.09710s from fe1.rs.github.com">GitHub</span> Inc. All rights reserved.</li> | |
| 502 | + <li><a href="/site/terms">Terms of Service</a></li> | |
| 503 | + <li><a href="/site/privacy">Privacy</a></li> | |
| 504 | + <li><a href="https://github.com/security">Security</a></li> | |
| 505 | + </ul> | |
| 506 | + </div> | |
| 507 | + </div><!-- /#footer --> | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + <!-- current locale: --> | |
| 513 | + <div class="locales"> | |
| 514 | + <div class="site"> | |
| 515 | + | |
| 516 | + <ul class="choices clearfix limited-locales"> | |
| 517 | + <li><span class="current">English</span></li> | |
| 518 | + | |
| 519 | + <li><a rel="nofollow" href="?locale=de">Deutsch</a></li> | |
| 520 | + | |
| 521 | + <li><a rel="nofollow" href="?locale=fr">Français</a></li> | |
| 522 | + | |
| 523 | + <li><a rel="nofollow" href="?locale=ja">日本語</a></li> | |
| 524 | + | |
| 525 | + <li><a rel="nofollow" href="?locale=pt-BR">Português (BR)</a></li> | |
| 526 | + | |
| 527 | + <li><a rel="nofollow" href="?locale=ru">Русский</a></li> | |
| 528 | + | |
| 529 | + <li><a rel="nofollow" href="?locale=zh">中文</a></li> | |
| 530 | + | |
| 531 | + <li class="all"><a href="#" class="minibutton btn-forward js-all-locales"><span><span class="icon"></span>See all available languages</span></a></li> | |
| 532 | + </ul> | |
| 533 | + | |
| 534 | + <div class="all-locales clearfix"> | |
| 535 | + <h3>Your current locale selection: <strong>English</strong>. Choose another?</h3> | |
| 536 | + | |
| 537 | + | |
| 538 | + <ul class="choices"> | |
| 539 | + | |
| 540 | + <li><a rel="nofollow" href="?locale=en">English</a></li> | |
| 541 | + | |
| 542 | + <li><a rel="nofollow" href="?locale=af">Afrikaans</a></li> | |
| 543 | + | |
| 544 | + <li><a rel="nofollow" href="?locale=ca">Català</a></li> | |
| 545 | + | |
| 546 | + <li><a rel="nofollow" href="?locale=cs">Čeština</a></li> | |
| 547 | + | |
| 548 | + </ul> | |
| 549 | + | |
| 550 | + <ul class="choices"> | |
| 551 | + | |
| 552 | + <li><a rel="nofollow" href="?locale=de">Deutsch</a></li> | |
| 553 | + | |
| 554 | + <li><a rel="nofollow" href="?locale=es">Español</a></li> | |
| 555 | + | |
| 556 | + <li><a rel="nofollow" href="?locale=fr">Français</a></li> | |
| 557 | + | |
| 558 | + <li><a rel="nofollow" href="?locale=hr">Hrvatski</a></li> | |
| 559 | + | |
| 560 | + </ul> | |
| 561 | + | |
| 562 | + <ul class="choices"> | |
| 563 | + | |
| 564 | + <li><a rel="nofollow" href="?locale=id">Indonesia</a></li> | |
| 565 | + | |
| 566 | + <li><a rel="nofollow" href="?locale=it">Italiano</a></li> | |
| 567 | + | |
| 568 | + <li><a rel="nofollow" href="?locale=ja">日本語</a></li> | |
| 569 | + | |
| 570 | + <li><a rel="nofollow" href="?locale=nl">Nederlands</a></li> | |
| 571 | + | |
| 572 | + </ul> | |
| 573 | + | |
| 574 | + <ul class="choices"> | |
| 575 | + | |
| 576 | + <li><a rel="nofollow" href="?locale=no">Norsk</a></li> | |
| 577 | + | |
| 578 | + <li><a rel="nofollow" href="?locale=pl">Polski</a></li> | |
| 579 | + | |
| 580 | + <li><a rel="nofollow" href="?locale=pt-BR">Português (BR)</a></li> | |
| 581 | + | |
| 582 | + <li><a rel="nofollow" href="?locale=ru">Русский</a></li> | |
| 583 | + | |
| 584 | + </ul> | |
| 585 | + | |
| 586 | + <ul class="choices"> | |
| 587 | + | |
| 588 | + <li><a rel="nofollow" href="?locale=sr">Српски</a></li> | |
| 589 | + | |
| 590 | + <li><a rel="nofollow" href="?locale=sv">Svenska</a></li> | |
| 591 | + | |
| 592 | + <li><a rel="nofollow" href="?locale=zh">中文</a></li> | |
| 593 | + | |
| 594 | + </ul> | |
| 595 | + | |
| 596 | + </div> | |
| 597 | + | |
| 598 | + </div> | |
| 599 | + <div class="fade"></div> | |
| 600 | + </div> | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + <script>window._auth_token = "0788e12631f37df2bd75592390a297816b6698da"</script> | |
| 605 | + <div id="keyboard_shortcuts_pane" style="display:none"> | |
| 606 | + <h2>Keyboard Shortcuts</h2> | |
| 607 | + | |
| 608 | + <div class="columns threecols"> | |
| 609 | + <div class="column first"> | |
| 610 | + <h3>Site wide shortcuts</h3> | |
| 611 | + <dl class="keyboard-mappings"> | |
| 612 | + <dt>s</dt> | |
| 613 | + <dd>Focus site search</dd> | |
| 614 | + </dl> | |
| 615 | + <dl class="keyboard-mappings"> | |
| 616 | + <dt>?</dt> | |
| 617 | + <dd>Bring up this help dialog</dd> | |
| 618 | + </dl> | |
| 619 | + </div><!-- /.column.first --> | |
| 620 | + <div class="column middle"> | |
| 621 | + <h3>Commit list</h3> | |
| 622 | + <dl class="keyboard-mappings"> | |
| 623 | + <dt>j</dt> | |
| 624 | + <dd>Move selected down</dd> | |
| 625 | + </dl> | |
| 626 | + <dl class="keyboard-mappings"> | |
| 627 | + <dt>k</dt> | |
| 628 | + <dd>Move selected up</dd> | |
| 629 | + </dl> | |
| 630 | + <dl class="keyboard-mappings"> | |
| 631 | + <dt>t</dt> | |
| 632 | + <dd>Open tree</dd> | |
| 633 | + </dl> | |
| 634 | + <dl class="keyboard-mappings"> | |
| 635 | + <dt>p</dt> | |
| 636 | + <dd>Open parent</dd> | |
| 637 | + </dl> | |
| 638 | + <dl class="keyboard-mappings"> | |
| 639 | + <dt>c <em>or</em> o <em>or</em> enter</dt> | |
| 640 | + <dd>Open commit</dd> | |
| 641 | + </dl> | |
| 642 | + </div><!-- /.column.first --> | |
| 643 | + <div class="column last"> | |
| 644 | + <h3>Pull request list</h3> | |
| 645 | + <dl class="keyboard-mappings"> | |
| 646 | + <dt>j</dt> | |
| 647 | + <dd>Move selected down</dd> | |
| 648 | + </dl> | |
| 649 | + <dl class="keyboard-mappings"> | |
| 650 | + <dt>k</dt> | |
| 651 | + <dd>Move selected up</dd> | |
| 652 | + </dl> | |
| 653 | + <dl class="keyboard-mappings"> | |
| 654 | + <dt>o <em>or</em> enter</dt> | |
| 655 | + <dd>Open issue</dd> | |
| 656 | + </dl> | |
| 657 | + </div><!-- /.columns.last --> | |
| 658 | + </div><!-- /.columns.equacols --> | |
| 659 | + | |
| 660 | + <div class="rule"></div> | |
| 661 | + | |
| 662 | + <h3>Issues</h3> | |
| 663 | + | |
| 664 | + <div class="columns threecols"> | |
| 665 | + <div class="column first"> | |
| 666 | + <dl class="keyboard-mappings"> | |
| 667 | + <dt>j</dt> | |
| 668 | + <dd>Move selected down</dd> | |
| 669 | + </dl> | |
| 670 | + <dl class="keyboard-mappings"> | |
| 671 | + <dt>k</dt> | |
| 672 | + <dd>Move selected up</dd> | |
| 673 | + </dl> | |
| 674 | + <dl class="keyboard-mappings"> | |
| 675 | + <dt>x</dt> | |
| 676 | + <dd>Toggle select target</dd> | |
| 677 | + </dl> | |
| 678 | + <dl class="keyboard-mappings"> | |
| 679 | + <dt>o <em>or</em> enter</dt> | |
| 680 | + <dd>Open issue</dd> | |
| 681 | + </dl> | |
| 682 | + </div><!-- /.column.first --> | |
| 683 | + <div class="column middle"> | |
| 684 | + <dl class="keyboard-mappings"> | |
| 685 | + <dt>I</dt> | |
| 686 | + <dd>Mark selected as read</dd> | |
| 687 | + </dl> | |
| 688 | + <dl class="keyboard-mappings"> | |
| 689 | + <dt>U</dt> | |
| 690 | + <dd>Mark selected as unread</dd> | |
| 691 | + </dl> | |
| 692 | + <dl class="keyboard-mappings"> | |
| 693 | + <dt>e</dt> | |
| 694 | + <dd>Close selected</dd> | |
| 695 | + </dl> | |
| 696 | + <dl class="keyboard-mappings"> | |
| 697 | + <dt>y</dt> | |
| 698 | + <dd>Remove selected from view</dd> | |
| 699 | + </dl> | |
| 700 | + </div><!-- /.column.middle --> | |
| 701 | + <div class="column last"> | |
| 702 | + <dl class="keyboard-mappings"> | |
| 703 | + <dt>c</dt> | |
| 704 | + <dd>Create issue</dd> | |
| 705 | + </dl> | |
| 706 | + <dl class="keyboard-mappings"> | |
| 707 | + <dt>l</dt> | |
| 708 | + <dd>Create label</dd> | |
| 709 | + </dl> | |
| 710 | + <dl class="keyboard-mappings"> | |
| 711 | + <dt>i</dt> | |
| 712 | + <dd>Back to inbox</dd> | |
| 713 | + </dl> | |
| 714 | + <dl class="keyboard-mappings"> | |
| 715 | + <dt>u</dt> | |
| 716 | + <dd>Back to issues</dd> | |
| 717 | + </dl> | |
| 718 | + <dl class="keyboard-mappings"> | |
| 719 | + <dt>/</dt> | |
| 720 | + <dd>Focus issues search</dd> | |
| 721 | + </dl> | |
| 722 | + </div> | |
| 723 | + </div> | |
| 724 | + | |
| 725 | + <div class="rule"></div> | |
| 726 | + | |
| 727 | + <h3>Network Graph</h3> | |
| 728 | + <div class="columns equacols"> | |
| 729 | + <div class="column first"> | |
| 730 | + <dl class="keyboard-mappings"> | |
| 731 | + <dt>← <em>or</em> h</dt> | |
| 732 | + <dd>Scroll left</dd> | |
| 733 | + </dl> | |
| 734 | + <dl class="keyboard-mappings"> | |
| 735 | + <dt>→ <em>or</em> l</dt> | |
| 736 | + <dd>Scroll right</dd> | |
| 737 | + </dl> | |
| 738 | + <dl class="keyboard-mappings"> | |
| 739 | + <dt>↑ <em>or</em> k</dt> | |
| 740 | + <dd>Scroll up</dd> | |
| 741 | + </dl> | |
| 742 | + <dl class="keyboard-mappings"> | |
| 743 | + <dt>↓ <em>or</em> j</dt> | |
| 744 | + <dd>Scroll down</dd> | |
| 745 | + </dl> | |
| 746 | + <dl class="keyboard-mappings"> | |
| 747 | + <dt>t</dt> | |
| 748 | + <dd>Toggle visibility of head labels</dd> | |
| 749 | + </dl> | |
| 750 | + </div><!-- /.column.first --> | |
| 751 | + <div class="column last"> | |
| 752 | + <dl class="keyboard-mappings"> | |
| 753 | + <dt>shift ← <em>or</em> shift h</dt> | |
| 754 | + <dd>Scroll all the way left</dd> | |
| 755 | + </dl> | |
| 756 | + <dl class="keyboard-mappings"> | |
| 757 | + <dt>shift → <em>or</em> shift l</dt> | |
| 758 | + <dd>Scroll all the way right</dd> | |
| 759 | + </dl> | |
| 760 | + <dl class="keyboard-mappings"> | |
| 761 | + <dt>shift ↑ <em>or</em> shift k</dt> | |
| 762 | + <dd>Scroll all the way up</dd> | |
| 763 | + </dl> | |
| 764 | + <dl class="keyboard-mappings"> | |
| 765 | + <dt>shift ↓ <em>or</em> shift j</dt> | |
| 766 | + <dd>Scroll all the way down</dd> | |
| 767 | + </dl> | |
| 768 | + </div><!-- /.column.last --> | |
| 769 | + </div> | |
| 770 | + | |
| 771 | +</div> | |
| 772 | + | |
| 773 | + | |
| 774 | + <!--[if IE 8]> | |
| 775 | + <script type="text/javascript" charset="utf-8"> | |
| 776 | + $(document.body).addClass("ie8") | |
| 777 | + </script> | |
| 778 | + <![endif]--> | |
| 779 | + | |
| 780 | + <!--[if IE 7]> | |
| 781 | + <script type="text/javascript" charset="utf-8"> | |
| 782 | + $(document.body).addClass("ie7") | |
| 783 | + </script> | |
| 784 | + <![endif]--> | |
| 785 | + | |
| 786 | + <script type="text/javascript"> | |
| 787 | + _kmq.push(['trackClick', 'entice-signup-button', 'Entice banner clicked']); | |
| 788 | + | |
| 789 | + </script> | |
| 790 | + | |
| 791 | + </body> | |
| 792 | +</html> | |
| 793 | + | ... | ... |
| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * @file | |
| 4 | + * User has successfully authenticated with Twitter. Access tokens saved to session and DB. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +/* Load required lib files. */ | |
| 8 | +session_name("openid"); | |
| 9 | +session_start(); | |
| 10 | +require_once('twitteroauth/twitteroauth.php'); | |
| 11 | +require_once('config.php'); | |
| 12 | + | |
| 13 | +/* If access tokens are not available redirect to connect page. */ | |
| 14 | +if (empty($_SESSION['access_token']) || empty($_SESSION['access_token']['oauth_token']) || empty($_SESSION['access_token']['oauth_token_secret'])) { | |
| 15 | + $_SESSION["openid"] = false; | |
| 16 | + session_destroy(); | |
| 17 | + header('Location: ../openid/login.php?login&erro=ok'); | |
| 18 | +} | |
| 19 | +/* Get user access tokens out of the session. */ | |
| 20 | +$access_token = $_SESSION['access_token']; | |
| 21 | + | |
| 22 | +/* Create a TwitterOauth object with consumer/user tokens. */ | |
| 23 | +$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token['oauth_token'], $access_token['oauth_token_secret']); | |
| 24 | + | |
| 25 | +/* If method is set change API call made. Test is called by default. */ | |
| 26 | +$content = $connection->get('account/verify_credentials'); | |
| 27 | + | |
| 28 | +$_SESSION["openid"] = true; | |
| 29 | +$_SESSION["openid_identifier"] = "http://twitter.com/".$content->screen_name; | |
| 30 | +$_SESSION["openidusuario"] = $content->screen_name; | |
| 31 | +$_SESSION["openidservico"] = "twitter"; | |
| 32 | +$_SESSION["openidimagem"] = $content->profile_image_url; | |
| 33 | +$_SESSION["openidnome"] = $content->name; | |
| 34 | +header('Location: ../openid/login.php'); | |
| 35 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | +<?php | |
| 2 | +$dadosurl = array_merge($_GET,$_POST); | |
| 3 | +require_once('config.php'); | |
| 4 | +/* Start session and load library. */ | |
| 5 | +session_name("openid"); | |
| 6 | +session_start(); | |
| 7 | + | |
| 8 | +require_once('twitteroauth/twitteroauth.php'); | |
| 9 | +//require_once('config.php'); | |
| 10 | + | |
| 11 | +/* Build TwitterOAuth object with client credentials. */ | |
| 12 | +$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET); | |
| 13 | + | |
| 14 | +/* Get temporary credentials. */ | |
| 15 | +$request_token = $connection->getRequestToken(OAUTH_CALLBACK); | |
| 16 | + | |
| 17 | +/* Save temporary credentials to session. */ | |
| 18 | +$_SESSION['oauth_token'] = $token = $request_token['oauth_token']; | |
| 19 | +$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret']; | |
| 20 | +$_SESSION['servico'] = "twitter"; | |
| 21 | + | |
| 22 | +/* If last connection failed don't display authorization link. */ | |
| 23 | +switch ($connection->http_code) { | |
| 24 | + case 200: | |
| 25 | + /* Build authorize URL and redirect user to Twitter. */ | |
| 26 | + $url = $connection->getAuthorizeURL($token); | |
| 27 | + header('Location: '.$url ); | |
| 28 | + break; | |
| 29 | + default: | |
| 30 | + /* Show notification if something went wrong. */ | |
| 31 | + echo 'Could not connect to Twitter. Refresh the page or try again later.'; | |
| 32 | +} | ... | ... |
| ... | ... | @@ -0,0 +1,374 @@ |
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * @file | |
| 4 | + * | |
| 5 | + */ | |
| 6 | + | |
| 7 | +/* Load required lib files. */ | |
| 8 | +session_start(); | |
| 9 | +require_once('twitteroauth/twitteroauth.php'); | |
| 10 | +require_once('config.php'); | |
| 11 | + | |
| 12 | +/* If access tokens are not available redirect to connect page. */ | |
| 13 | +if (empty($_SESSION['access_token']) || empty($_SESSION['access_token']['oauth_token']) || empty($_SESSION['access_token']['oauth_token_secret'])) { | |
| 14 | + header('Location: ./clearsessions.php'); | |
| 15 | +} | |
| 16 | +/* Get user access tokens out of the session. */ | |
| 17 | +$access_token = $_SESSION['access_token']; | |
| 18 | + | |
| 19 | +/* Create a TwitterOauth object with consumer/user tokens. */ | |
| 20 | +$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token['oauth_token'], $access_token['oauth_token_secret']); | |
| 21 | + | |
| 22 | +/* If method is set change API call made. Test is called by default. */ | |
| 23 | +$content = $connection->get('account/rate_limit_status'); | |
| 24 | +echo "Current API hits remaining: {$content->remaining_hits}."; | |
| 25 | + | |
| 26 | +/* Get logged in user to help with tests. */ | |
| 27 | +$user = $connection->get('account/verify_credentials'); | |
| 28 | + | |
| 29 | +$active = FALSE; | |
| 30 | +if (empty($active) || empty($_GET['confirmed']) || $_GET['confirmed'] !== 'TRUE') { | |
| 31 | + echo '<h1>Warning! This page will make many requests to Twitter.</h1>'; | |
| 32 | + echo '<h3>Performing these test might max out your rate limit.</h3>'; | |
| 33 | + echo '<h3>Statuses/DMs will be created and deleted. Accounts will be un/followed.</h3>'; | |
| 34 | + echo '<h3>Profile information/design will be changed.</h3>'; | |
| 35 | + echo '<h2>USE A DEV ACCOUNT!</h2>'; | |
| 36 | + echo '<h4>Before use you must set $active = TRUE in test.php</h4>'; | |
| 37 | + echo '<a href="./test.php?confirmed=TRUE">Continue</a> or <a href="./index.php">go back</a>.'; | |
| 38 | + exit; | |
| 39 | +} | |
| 40 | + | |
| 41 | +function twitteroauth_row($method, $response, $http_code, $parameters = '') { | |
| 42 | + echo '<tr>'; | |
| 43 | + echo "<td><b>{$method}</b></td>"; | |
| 44 | + switch ($http_code) { | |
| 45 | + case '200': | |
| 46 | + case '304': | |
| 47 | + $color = 'green'; | |
| 48 | + break; | |
| 49 | + case '400': | |
| 50 | + case '401': | |
| 51 | + case '403': | |
| 52 | + case '404': | |
| 53 | + case '406': | |
| 54 | + $color = 'red'; | |
| 55 | + break; | |
| 56 | + case '500': | |
| 57 | + case '502': | |
| 58 | + case '503': | |
| 59 | + $color = 'orange'; | |
| 60 | + break; | |
| 61 | + default: | |
| 62 | + $color = 'grey'; | |
| 63 | + } | |
| 64 | + echo "<td style='background: {$color};'>{$http_code}</td>"; | |
| 65 | + if (!is_string($response)) { | |
| 66 | + $response = print_r($response, TRUE); | |
| 67 | + } | |
| 68 | + if (!is_string($parameters)) { | |
| 69 | + $parameters = print_r($parameters, TRUE); | |
| 70 | + } | |
| 71 | + echo '<td>', strlen($response), '</td>'; | |
| 72 | + echo '<td>', $parameters, '</td>'; | |
| 73 | + echo '</tr><tr>'; | |
| 74 | + echo '<td colspan="4">', substr($response, 0, 400), '...</td>'; | |
| 75 | + echo '</tr>'; | |
| 76 | + | |
| 77 | +} | |
| 78 | + | |
| 79 | +function twitteroauth_header($header) { | |
| 80 | + echo '<tr><th colspan="4" style="background: grey;">', $header, '</th></tr>'; | |
| 81 | +} | |
| 82 | + | |
| 83 | +/* Start table. */ | |
| 84 | +echo '<br><br>'; | |
| 85 | +echo '<table border="1" cellpadding="2" cellspacing="0">'; | |
| 86 | +echo '<tr>'; | |
| 87 | +echo '<th>API Method</th>'; | |
| 88 | +echo '<th>HTTP Code</th>'; | |
| 89 | +echo '<th>Response Length</th>'; | |
| 90 | +echo '<th>Parameters</th>'; | |
| 91 | +echo '</tr><tr>'; | |
| 92 | +echo '<th colspan="4">Response Snippet</th>'; | |
| 93 | +echo '</tr>'; | |
| 94 | + | |
| 95 | +/** | |
| 96 | + * Help Methods. | |
| 97 | + */ | |
| 98 | +twitteroauth_header('Help Methods'); | |
| 99 | + | |
| 100 | +/* help/test */ | |
| 101 | +twitteroauth_row('help/test', $connection->get('help/test'), $connection->http_code); | |
| 102 | + | |
| 103 | + | |
| 104 | +/** | |
| 105 | + * Timeline Methods. | |
| 106 | + */ | |
| 107 | +twitteroauth_header('Timeline Methods'); | |
| 108 | + | |
| 109 | +/* statuses/public_timeline */ | |
| 110 | +twitteroauth_row('statuses/public_timeline', $connection->get('statuses/public_timeline'), $connection->http_code); | |
| 111 | + | |
| 112 | +/* statuses/public_timeline */ | |
| 113 | +twitteroauth_row('statuses/home_timeline', $connection->get('statuses/home_timeline'), $connection->http_code); | |
| 114 | + | |
| 115 | +/* statuses/friends_timeline */ | |
| 116 | +twitteroauth_row('statuses/friends_timeline', $connection->get('statuses/friends_timeline'), $connection->http_code); | |
| 117 | + | |
| 118 | +/* statuses/user_timeline */ | |
| 119 | +twitteroauth_row('statuses/user_timeline', $connection->get('statuses/user_timeline'), $connection->http_code); | |
| 120 | + | |
| 121 | +/* statuses/mentions */ | |
| 122 | +twitteroauth_row('statuses/mentions', $connection->get('statuses/mentions'), $connection->http_code); | |
| 123 | + | |
| 124 | +/* statuses/retweeted_by_me */ | |
| 125 | +twitteroauth_row('statuses/retweeted_by_me', $connection->get('statuses/retweeted_by_me'), $connection->http_code); | |
| 126 | + | |
| 127 | +/* statuses/retweeted_to_me */ | |
| 128 | +twitteroauth_row('statuses/retweeted_to_me', $connection->get('statuses/retweeted_to_me'), $connection->http_code); | |
| 129 | + | |
| 130 | +/* statuses/retweets_of_me */ | |
| 131 | +twitteroauth_row('statuses/retweets_of_me', $connection->get('statuses/retweets_of_me'), $connection->http_code); | |
| 132 | + | |
| 133 | + | |
| 134 | +/** | |
| 135 | + * Status Methods. | |
| 136 | + */ | |
| 137 | +twitteroauth_header('Status Methods'); | |
| 138 | + | |
| 139 | +/* statuses/update */ | |
| 140 | +date_default_timezone_set('GMT'); | |
| 141 | +$parameters = array('status' => date(DATE_RFC822)); | |
| 142 | +$status = $connection->post('statuses/update', $parameters); | |
| 143 | +twitteroauth_row('statuses/update', $status, $connection->http_code, $parameters); | |
| 144 | + | |
| 145 | +/* statuses/show */ | |
| 146 | +$method = "statuses/show/{$status->id}"; | |
| 147 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 148 | + | |
| 149 | +/* statuses/destroy */ | |
| 150 | +$method = "statuses/destroy/{$status->id}"; | |
| 151 | +twitteroauth_row($method, $connection->delete($method), $connection->http_code); | |
| 152 | + | |
| 153 | +/* statuses/retweet */ | |
| 154 | +$method = 'statuses/retweet/6242973112'; | |
| 155 | +twitteroauth_row($method, $connection->post($method), $connection->http_code); | |
| 156 | + | |
| 157 | +/* statuses/retweets */ | |
| 158 | +$method = 'statuses/retweets/6242973112'; | |
| 159 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 160 | + | |
| 161 | + | |
| 162 | +/** | |
| 163 | + * User Methods. | |
| 164 | + */ | |
| 165 | +twitteroauth_header('User Methods'); | |
| 166 | + | |
| 167 | +/* users/show */ | |
| 168 | +$method = 'users/show/27831060'; | |
| 169 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 170 | + | |
| 171 | +/* users/search */ | |
| 172 | +$parameters = array('q' => 'oauth'); | |
| 173 | +twitteroauth_row('users/search', $connection->get('users/search', $parameters), $connection->http_code, $parameters); | |
| 174 | + | |
| 175 | +/* statuses/friends */ | |
| 176 | +$method = 'statuses/friends/27831060'; | |
| 177 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 178 | + | |
| 179 | +/* statuses/followers */ | |
| 180 | +$method = 'statuses/followers/27831060'; | |
| 181 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 182 | + | |
| 183 | + | |
| 184 | +/** | |
| 185 | + * List Methods. | |
| 186 | + */ | |
| 187 | +twitteroauth_header('List Methods'); | |
| 188 | + | |
| 189 | +/* POST lists */ | |
| 190 | +$method = "{$user->screen_name}/lists"; | |
| 191 | +$parameters = array('name' => 'Twitter OAuth'); | |
| 192 | +$list = $connection->post($method, $parameters); | |
| 193 | +twitteroauth_row($method, $list, $connection->http_code, $parameters); | |
| 194 | + | |
| 195 | +/* POST lists id */ | |
| 196 | +$method = "{$user->screen_name}/lists/{$list->id}"; | |
| 197 | +$parameters = array('name' => 'Twitter OAuth List 2'); | |
| 198 | +$list = $connection->post($method, $parameters); | |
| 199 | +twitteroauth_row($method, $list, $connection->http_code, $parameters); | |
| 200 | + | |
| 201 | +/* GET lists */ | |
| 202 | +$method = "{$user->screen_name}/lists"; | |
| 203 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 204 | + | |
| 205 | +/* GET lists id */ | |
| 206 | +$method = "{$user->screen_name}/lists/{$list->id}"; | |
| 207 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 208 | + | |
| 209 | +/* DELETE list */ | |
| 210 | +$method = "{$user->screen_name}/lists/{$list->id}"; | |
| 211 | +twitteroauth_row($method, $connection->delete($method), $connection->http_code); | |
| 212 | + | |
| 213 | +/* GET list statuses */ | |
| 214 | +$method = "oauthlib/lists/4097351/statuses"; | |
| 215 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 216 | + | |
| 217 | +/* GET list members */ | |
| 218 | +$method = "{$user->screen_name}/lists/memberships"; | |
| 219 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 220 | + | |
| 221 | + | |
| 222 | +/* GET list subscriptions */ | |
| 223 | +$method = "{$user->screen_name}/lists/subscriptions"; | |
| 224 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 225 | + | |
| 226 | + | |
| 227 | +/** | |
| 228 | + * List Members Methods. | |
| 229 | + */ | |
| 230 | +twitteroauth_header('List Members Methods'); | |
| 231 | + | |
| 232 | +/* Create temp list for list member methods. */ | |
| 233 | +$method = "{$user->screen_name}/lists"; | |
| 234 | +$parameters = array('name' => 'Twitter OAuth Temp'); | |
| 235 | +$list = $connection->post($method, $parameters); | |
| 236 | + | |
| 237 | + | |
| 238 | +/* POST list members */ | |
| 239 | +$parameters = array('id' => 27831060); | |
| 240 | +$method = "{$user->screen_name}/{$list->id}/members"; | |
| 241 | +twitteroauth_row($method, $connection->post($method, $parameters), $connection->http_code, $parameters); | |
| 242 | + | |
| 243 | +/* GET list members */ | |
| 244 | +$method = "{$user->screen_name}/{$list->id}/members"; | |
| 245 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 246 | + | |
| 247 | +/* GET list members id */ | |
| 248 | +$method = "{$user->screen_name}/{$list->id}/members/27831060"; | |
| 249 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 250 | + | |
| 251 | +/* DELETE list members */ | |
| 252 | +$parameters = array('id' => 27831060); | |
| 253 | +$method = "{$user->screen_name}/{$list->id}/members"; | |
| 254 | +twitteroauth_row($method, $connection->delete($method, $parameters), $connection->http_code, $parameters); | |
| 255 | + | |
| 256 | +/* Delete the temp list */ | |
| 257 | +$method = "{$user->screen_name}/lists/{$list->id}"; | |
| 258 | +$connection->delete($method); | |
| 259 | + | |
| 260 | + | |
| 261 | +/** | |
| 262 | + * List Subscribers Methods. | |
| 263 | + */ | |
| 264 | +twitteroauth_header('List Subscribers Methods'); | |
| 265 | + | |
| 266 | + | |
| 267 | +/* POST list subscribers */ | |
| 268 | +$method = 'oauthlib/test-list/subscribers'; | |
| 269 | +twitteroauth_row($method, $connection->post($method), $connection->http_code); | |
| 270 | + | |
| 271 | +/* GET list subscribers */ | |
| 272 | +$method = 'oauthlib/test-list/subscribers'; | |
| 273 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 274 | + | |
| 275 | +/* GET list subscribers id */ | |
| 276 | +$method = "oauthlib/test-list/subscribers/{$user->id}"; | |
| 277 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 278 | + | |
| 279 | +/* DELETE list subscribers */ | |
| 280 | +$method = 'oauthlib/test-list/subscribers'; | |
| 281 | +twitteroauth_row($method, $connection->delete($method), $connection->http_code); | |
| 282 | + | |
| 283 | + | |
| 284 | +/** | |
| 285 | + * Direct Message Methdos. | |
| 286 | + */ | |
| 287 | +twitteroauth_header('Direct Message Methods'); | |
| 288 | + | |
| 289 | +/* direct_messages/new */ | |
| 290 | +$parameters = array('user_id' => $user->id, 'text' => 'Testing out @oauthlib code'); | |
| 291 | +$method = 'direct_messages/new'; | |
| 292 | +$dm = $connection->post($method, $parameters); | |
| 293 | +twitteroauth_row($method, $dm, $connection->http_code, $parameters); | |
| 294 | + | |
| 295 | +/* direct_messages */ | |
| 296 | +$method = 'direct_messages'; | |
| 297 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 298 | + | |
| 299 | +/* direct_messages/sent */ | |
| 300 | +$method = 'direct_messages/sent'; | |
| 301 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 302 | + | |
| 303 | +/* direct_messages/sent */ | |
| 304 | +$method = "direct_messages/destroy/{$dm->id}"; | |
| 305 | +twitteroauth_row($method, $connection->delete($method), $connection->http_code); | |
| 306 | + | |
| 307 | + | |
| 308 | +/** | |
| 309 | + * Friendships Methods. | |
| 310 | + */ | |
| 311 | +twitteroauth_header('Friendships Methods'); | |
| 312 | + | |
| 313 | +/* friendships/create */ | |
| 314 | +$method = 'friendships/create/93915746'; | |
| 315 | +twitteroauth_row($method, $connection->post($method), $connection->http_code); | |
| 316 | + | |
| 317 | +/* friendships/show */ | |
| 318 | +$parameters = array('target_id' => 27831060); | |
| 319 | +$method = 'friendships/show'; | |
| 320 | +twitteroauth_row($method, $connection->get($method, $parameters), $connection->http_code, $parameters); | |
| 321 | + | |
| 322 | +/* friendships/destroy */ | |
| 323 | +$method = 'friendships/destroy/93915746'; | |
| 324 | +twitteroauth_row($method, $connection->post($method), $connection->http_code); | |
| 325 | + | |
| 326 | + | |
| 327 | +/** | |
| 328 | + * Social Graph Methods. | |
| 329 | + */ | |
| 330 | +twitteroauth_header('Social Graph Methods'); | |
| 331 | + | |
| 332 | +/* friends/ids */ | |
| 333 | +$method = 'friends/ids'; | |
| 334 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 335 | + | |
| 336 | +/* friends/ids */ | |
| 337 | +$method = 'friends/ids'; | |
| 338 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 339 | + | |
| 340 | + | |
| 341 | +/** | |
| 342 | + * Account Methods. | |
| 343 | + */ | |
| 344 | +twitteroauth_header('Account Methods'); | |
| 345 | + | |
| 346 | +/* account/verify_credentials */ | |
| 347 | +$method = 'account/verify_credentials'; | |
| 348 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 349 | + | |
| 350 | +/* account/rate_limit_status */ | |
| 351 | +$method = 'account/rate_limit_status'; | |
| 352 | +twitteroauth_row($method, $connection->get($method), $connection->http_code); | |
| 353 | + | |
| 354 | +/* account/update_profile_colors */ | |
| 355 | +$parameters = array('profile_background_color' => 'fff'); | |
| 356 | +$method = 'account/update_profile_colors'; | |
| 357 | +twitteroauth_row($method, $connection->post($method, $parameters), $connection->http_code, $parameters); | |
| 358 | + | |
| 359 | +/* account/update_profile */ | |
| 360 | +$parameters = array('location' => 'Teh internets'); | |
| 361 | +$method = 'account/update_profile'; | |
| 362 | +twitteroauth_row($method, $connection->post($method, $parameters), $connection->http_code, $parameters); | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | +/** | |
| 368 | + * OAuth Methods. | |
| 369 | + */ | |
| 370 | +twitteroauth_header('OAuth Methods'); | |
| 371 | + | |
| 372 | +/* oauth/request_token */ | |
| 373 | +$oauth = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET); | |
| 374 | +twitteroauth_row('oauth/reqeust_token', $oauth->getRequestToken(), $oauth->http_code); | ... | ... |
| ... | ... | @@ -0,0 +1,874 @@ |
| 1 | +<?php | |
| 2 | +// vim: foldmethod=marker | |
| 3 | + | |
| 4 | +/* Generic exception class | |
| 5 | + */ | |
| 6 | +class OAuthException extends Exception { | |
| 7 | + // pass | |
| 8 | +} | |
| 9 | + | |
| 10 | +class OAuthConsumer { | |
| 11 | + public $key; | |
| 12 | + public $secret; | |
| 13 | + | |
| 14 | + function __construct($key, $secret, $callback_url=NULL) { | |
| 15 | + $this->key = $key; | |
| 16 | + $this->secret = $secret; | |
| 17 | + $this->callback_url = $callback_url; | |
| 18 | + } | |
| 19 | + | |
| 20 | + function __toString() { | |
| 21 | + return "OAuthConsumer[key=$this->key,secret=$this->secret]"; | |
| 22 | + } | |
| 23 | +} | |
| 24 | + | |
| 25 | +class OAuthToken { | |
| 26 | + // access tokens and request tokens | |
| 27 | + public $key; | |
| 28 | + public $secret; | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * key = the token | |
| 32 | + * secret = the token secret | |
| 33 | + */ | |
| 34 | + function __construct($key, $secret) { | |
| 35 | + $this->key = $key; | |
| 36 | + $this->secret = $secret; | |
| 37 | + } | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * generates the basic string serialization of a token that a server | |
| 41 | + * would respond to request_token and access_token calls with | |
| 42 | + */ | |
| 43 | + function to_string() { | |
| 44 | + return "oauth_token=" . | |
| 45 | + OAuthUtil::urlencode_rfc3986($this->key) . | |
| 46 | + "&oauth_token_secret=" . | |
| 47 | + OAuthUtil::urlencode_rfc3986($this->secret); | |
| 48 | + } | |
| 49 | + | |
| 50 | + function __toString() { | |
| 51 | + return $this->to_string(); | |
| 52 | + } | |
| 53 | +} | |
| 54 | + | |
| 55 | +/** | |
| 56 | + * A class for implementing a Signature Method | |
| 57 | + * See section 9 ("Signing Requests") in the spec | |
| 58 | + */ | |
| 59 | +abstract class OAuthSignatureMethod { | |
| 60 | + /** | |
| 61 | + * Needs to return the name of the Signature Method (ie HMAC-SHA1) | |
| 62 | + * @return string | |
| 63 | + */ | |
| 64 | + abstract public function get_name(); | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Build up the signature | |
| 68 | + * NOTE: The output of this function MUST NOT be urlencoded. | |
| 69 | + * the encoding is handled in OAuthRequest when the final | |
| 70 | + * request is serialized | |
| 71 | + * @param OAuthRequest $request | |
| 72 | + * @param OAuthConsumer $consumer | |
| 73 | + * @param OAuthToken $token | |
| 74 | + * @return string | |
| 75 | + */ | |
| 76 | + abstract public function build_signature($request, $consumer, $token); | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * Verifies that a given signature is correct | |
| 80 | + * @param OAuthRequest $request | |
| 81 | + * @param OAuthConsumer $consumer | |
| 82 | + * @param OAuthToken $token | |
| 83 | + * @param string $signature | |
| 84 | + * @return bool | |
| 85 | + */ | |
| 86 | + public function check_signature($request, $consumer, $token, $signature) { | |
| 87 | + $built = $this->build_signature($request, $consumer, $token); | |
| 88 | + return $built == $signature; | |
| 89 | + } | |
| 90 | +} | |
| 91 | + | |
| 92 | +/** | |
| 93 | + * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] | |
| 94 | + * where the Signature Base String is the text and the key is the concatenated values (each first | |
| 95 | + * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' | |
| 96 | + * character (ASCII code 38) even if empty. | |
| 97 | + * - Chapter 9.2 ("HMAC-SHA1") | |
| 98 | + */ | |
| 99 | +class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { | |
| 100 | + function get_name() { | |
| 101 | + return "HMAC-SHA1"; | |
| 102 | + } | |
| 103 | + | |
| 104 | + public function build_signature($request, $consumer, $token) { | |
| 105 | + $base_string = $request->get_signature_base_string(); | |
| 106 | + $request->base_string = $base_string; | |
| 107 | + | |
| 108 | + $key_parts = array( | |
| 109 | + $consumer->secret, | |
| 110 | + ($token) ? $token->secret : "" | |
| 111 | + ); | |
| 112 | + | |
| 113 | + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); | |
| 114 | + $key = implode('&', $key_parts); | |
| 115 | + | |
| 116 | + return base64_encode(hash_hmac('sha1', $base_string, $key, true)); | |
| 117 | + } | |
| 118 | +} | |
| 119 | + | |
| 120 | +/** | |
| 121 | + * The PLAINTEXT method does not provide any security protection and SHOULD only be used | |
| 122 | + * over a secure channel such as HTTPS. It does not use the Signature Base String. | |
| 123 | + * - Chapter 9.4 ("PLAINTEXT") | |
| 124 | + */ | |
| 125 | +class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { | |
| 126 | + public function get_name() { | |
| 127 | + return "PLAINTEXT"; | |
| 128 | + } | |
| 129 | + | |
| 130 | + /** | |
| 131 | + * oauth_signature is set to the concatenated encoded values of the Consumer Secret and | |
| 132 | + * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is | |
| 133 | + * empty. The result MUST be encoded again. | |
| 134 | + * - Chapter 9.4.1 ("Generating Signatures") | |
| 135 | + * | |
| 136 | + * Please note that the second encoding MUST NOT happen in the SignatureMethod, as | |
| 137 | + * OAuthRequest handles this! | |
| 138 | + */ | |
| 139 | + public function build_signature($request, $consumer, $token) { | |
| 140 | + $key_parts = array( | |
| 141 | + $consumer->secret, | |
| 142 | + ($token) ? $token->secret : "" | |
| 143 | + ); | |
| 144 | + | |
| 145 | + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); | |
| 146 | + $key = implode('&', $key_parts); | |
| 147 | + $request->base_string = $key; | |
| 148 | + | |
| 149 | + return $key; | |
| 150 | + } | |
| 151 | +} | |
| 152 | + | |
| 153 | +/** | |
| 154 | + * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in | |
| 155 | + * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for | |
| 156 | + * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a | |
| 157 | + * verified way to the Service Provider, in a manner which is beyond the scope of this | |
| 158 | + * specification. | |
| 159 | + * - Chapter 9.3 ("RSA-SHA1") | |
| 160 | + */ | |
| 161 | +abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { | |
| 162 | + public function get_name() { | |
| 163 | + return "RSA-SHA1"; | |
| 164 | + } | |
| 165 | + | |
| 166 | + // Up to the SP to implement this lookup of keys. Possible ideas are: | |
| 167 | + // (1) do a lookup in a table of trusted certs keyed off of consumer | |
| 168 | + // (2) fetch via http using a url provided by the requester | |
| 169 | + // (3) some sort of specific discovery code based on request | |
| 170 | + // | |
| 171 | + // Either way should return a string representation of the certificate | |
| 172 | + protected abstract function fetch_public_cert(&$request); | |
| 173 | + | |
| 174 | + // Up to the SP to implement this lookup of keys. Possible ideas are: | |
| 175 | + // (1) do a lookup in a table of trusted certs keyed off of consumer | |
| 176 | + // | |
| 177 | + // Either way should return a string representation of the certificate | |
| 178 | + protected abstract function fetch_private_cert(&$request); | |
| 179 | + | |
| 180 | + public function build_signature($request, $consumer, $token) { | |
| 181 | + $base_string = $request->get_signature_base_string(); | |
| 182 | + $request->base_string = $base_string; | |
| 183 | + | |
| 184 | + // Fetch the private key cert based on the request | |
| 185 | + $cert = $this->fetch_private_cert($request); | |
| 186 | + | |
| 187 | + // Pull the private key ID from the certificate | |
| 188 | + $privatekeyid = openssl_get_privatekey($cert); | |
| 189 | + | |
| 190 | + // Sign using the key | |
| 191 | + $ok = openssl_sign($base_string, $signature, $privatekeyid); | |
| 192 | + | |
| 193 | + // Release the key resource | |
| 194 | + openssl_free_key($privatekeyid); | |
| 195 | + | |
| 196 | + return base64_encode($signature); | |
| 197 | + } | |
| 198 | + | |
| 199 | + public function check_signature($request, $consumer, $token, $signature) { | |
| 200 | + $decoded_sig = base64_decode($signature); | |
| 201 | + | |
| 202 | + $base_string = $request->get_signature_base_string(); | |
| 203 | + | |
| 204 | + // Fetch the public key cert based on the request | |
| 205 | + $cert = $this->fetch_public_cert($request); | |
| 206 | + | |
| 207 | + // Pull the public key ID from the certificate | |
| 208 | + $publickeyid = openssl_get_publickey($cert); | |
| 209 | + | |
| 210 | + // Check the computed signature against the one passed in the query | |
| 211 | + $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); | |
| 212 | + | |
| 213 | + // Release the key resource | |
| 214 | + openssl_free_key($publickeyid); | |
| 215 | + | |
| 216 | + return $ok == 1; | |
| 217 | + } | |
| 218 | +} | |
| 219 | + | |
| 220 | +class OAuthRequest { | |
| 221 | + private $parameters; | |
| 222 | + private $http_method; | |
| 223 | + private $http_url; | |
| 224 | + // for debug purposes | |
| 225 | + public $base_string; | |
| 226 | + public static $version = '1.0'; | |
| 227 | + public static $POST_INPUT = 'php://input'; | |
| 228 | + | |
| 229 | + function __construct($http_method, $http_url, $parameters=NULL) { | |
| 230 | + @$parameters or $parameters = array(); | |
| 231 | + $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters); | |
| 232 | + $this->parameters = $parameters; | |
| 233 | + $this->http_method = $http_method; | |
| 234 | + $this->http_url = $http_url; | |
| 235 | + } | |
| 236 | + | |
| 237 | + | |
| 238 | + /** | |
| 239 | + * attempt to build up a request from what was passed to the server | |
| 240 | + */ | |
| 241 | + public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { | |
| 242 | + $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") | |
| 243 | + ? 'http' | |
| 244 | + : 'https'; | |
| 245 | + @$http_url or $http_url = $scheme . | |
| 246 | + '://' . $_SERVER['HTTP_HOST'] . | |
| 247 | + ':' . | |
| 248 | + $_SERVER['SERVER_PORT'] . | |
| 249 | + $_SERVER['REQUEST_URI']; | |
| 250 | + @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; | |
| 251 | + | |
| 252 | + // We weren't handed any parameters, so let's find the ones relevant to | |
| 253 | + // this request. | |
| 254 | + // If you run XML-RPC or similar you should use this to provide your own | |
| 255 | + // parsed parameter-list | |
| 256 | + if (!$parameters) { | |
| 257 | + // Find request headers | |
| 258 | + $request_headers = OAuthUtil::get_headers(); | |
| 259 | + | |
| 260 | + // Parse the query-string to find GET parameters | |
| 261 | + $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); | |
| 262 | + | |
| 263 | + // It's a POST request of the proper content-type, so parse POST | |
| 264 | + // parameters and add those overriding any duplicates from GET | |
| 265 | + if ($http_method == "POST" | |
| 266 | + && @strstr($request_headers["Content-Type"], | |
| 267 | + "application/x-www-form-urlencoded") | |
| 268 | + ) { | |
| 269 | + $post_data = OAuthUtil::parse_parameters( | |
| 270 | + file_get_contents(self::$POST_INPUT) | |
| 271 | + ); | |
| 272 | + $parameters = array_merge($parameters, $post_data); | |
| 273 | + } | |
| 274 | + | |
| 275 | + // We have a Authorization-header with OAuth data. Parse the header | |
| 276 | + // and add those overriding any duplicates from GET or POST | |
| 277 | + if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { | |
| 278 | + $header_parameters = OAuthUtil::split_header( | |
| 279 | + $request_headers['Authorization'] | |
| 280 | + ); | |
| 281 | + $parameters = array_merge($parameters, $header_parameters); | |
| 282 | + } | |
| 283 | + | |
| 284 | + } | |
| 285 | + | |
| 286 | + return new OAuthRequest($http_method, $http_url, $parameters); | |
| 287 | + } | |
| 288 | + | |
| 289 | + /** | |
| 290 | + * pretty much a helper function to set up the request | |
| 291 | + */ | |
| 292 | + public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { | |
| 293 | + @$parameters or $parameters = array(); | |
| 294 | + $defaults = array("oauth_version" => OAuthRequest::$version, | |
| 295 | + "oauth_nonce" => OAuthRequest::generate_nonce(), | |
| 296 | + "oauth_timestamp" => OAuthRequest::generate_timestamp(), | |
| 297 | + "oauth_consumer_key" => $consumer->key); | |
| 298 | + if ($token) | |
| 299 | + $defaults['oauth_token'] = $token->key; | |
| 300 | + | |
| 301 | + $parameters = array_merge($defaults, $parameters); | |
| 302 | + | |
| 303 | + return new OAuthRequest($http_method, $http_url, $parameters); | |
| 304 | + } | |
| 305 | + | |
| 306 | + public function set_parameter($name, $value, $allow_duplicates = true) { | |
| 307 | + if ($allow_duplicates && isset($this->parameters[$name])) { | |
| 308 | + // We have already added parameter(s) with this name, so add to the list | |
| 309 | + if (is_scalar($this->parameters[$name])) { | |
| 310 | + // This is the first duplicate, so transform scalar (string) | |
| 311 | + // into an array so we can add the duplicates | |
| 312 | + $this->parameters[$name] = array($this->parameters[$name]); | |
| 313 | + } | |
| 314 | + | |
| 315 | + $this->parameters[$name][] = $value; | |
| 316 | + } else { | |
| 317 | + $this->parameters[$name] = $value; | |
| 318 | + } | |
| 319 | + } | |
| 320 | + | |
| 321 | + public function get_parameter($name) { | |
| 322 | + return isset($this->parameters[$name]) ? $this->parameters[$name] : null; | |
| 323 | + } | |
| 324 | + | |
| 325 | + public function get_parameters() { | |
| 326 | + return $this->parameters; | |
| 327 | + } | |
| 328 | + | |
| 329 | + public function unset_parameter($name) { | |
| 330 | + unset($this->parameters[$name]); | |
| 331 | + } | |
| 332 | + | |
| 333 | + /** | |
| 334 | + * The request parameters, sorted and concatenated into a normalized string. | |
| 335 | + * @return string | |
| 336 | + */ | |
| 337 | + public function get_signable_parameters() { | |
| 338 | + // Grab all parameters | |
| 339 | + $params = $this->parameters; | |
| 340 | + | |
| 341 | + // Remove oauth_signature if present | |
| 342 | + // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") | |
| 343 | + if (isset($params['oauth_signature'])) { | |
| 344 | + unset($params['oauth_signature']); | |
| 345 | + } | |
| 346 | + | |
| 347 | + return OAuthUtil::build_http_query($params); | |
| 348 | + } | |
| 349 | + | |
| 350 | + /** | |
| 351 | + * Returns the base string of this request | |
| 352 | + * | |
| 353 | + * The base string defined as the method, the url | |
| 354 | + * and the parameters (normalized), each urlencoded | |
| 355 | + * and the concated with &. | |
| 356 | + */ | |
| 357 | + public function get_signature_base_string() { | |
| 358 | + $parts = array( | |
| 359 | + $this->get_normalized_http_method(), | |
| 360 | + $this->get_normalized_http_url(), | |
| 361 | + $this->get_signable_parameters() | |
| 362 | + ); | |
| 363 | + | |
| 364 | + $parts = OAuthUtil::urlencode_rfc3986($parts); | |
| 365 | + | |
| 366 | + return implode('&', $parts); | |
| 367 | + } | |
| 368 | + | |
| 369 | + /** | |
| 370 | + * just uppercases the http method | |
| 371 | + */ | |
| 372 | + public function get_normalized_http_method() { | |
| 373 | + return strtoupper($this->http_method); | |
| 374 | + } | |
| 375 | + | |
| 376 | + /** | |
| 377 | + * parses the url and rebuilds it to be | |
| 378 | + * scheme://host/path | |
| 379 | + */ | |
| 380 | + public function get_normalized_http_url() { | |
| 381 | + $parts = parse_url($this->http_url); | |
| 382 | + | |
| 383 | + $port = @$parts['port']; | |
| 384 | + $scheme = $parts['scheme']; | |
| 385 | + $host = $parts['host']; | |
| 386 | + $path = @$parts['path']; | |
| 387 | + | |
| 388 | + $port or $port = ($scheme == 'https') ? '443' : '80'; | |
| 389 | + | |
| 390 | + if (($scheme == 'https' && $port != '443') | |
| 391 | + || ($scheme == 'http' && $port != '80')) { | |
| 392 | + $host = "$host:$port"; | |
| 393 | + } | |
| 394 | + return "$scheme://$host$path"; | |
| 395 | + } | |
| 396 | + | |
| 397 | + /** | |
| 398 | + * builds a url usable for a GET request | |
| 399 | + */ | |
| 400 | + public function to_url() { | |
| 401 | + $post_data = $this->to_postdata(); | |
| 402 | + $out = $this->get_normalized_http_url(); | |
| 403 | + if ($post_data) { | |
| 404 | + $out .= '?'.$post_data; | |
| 405 | + } | |
| 406 | + return $out; | |
| 407 | + } | |
| 408 | + | |
| 409 | + /** | |
| 410 | + * builds the data one would send in a POST request | |
| 411 | + */ | |
| 412 | + public function to_postdata() { | |
| 413 | + return OAuthUtil::build_http_query($this->parameters); | |
| 414 | + } | |
| 415 | + | |
| 416 | + /** | |
| 417 | + * builds the Authorization: header | |
| 418 | + */ | |
| 419 | + public function to_header($realm=null) { | |
| 420 | + $first = true; | |
| 421 | + if($realm) { | |
| 422 | + $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; | |
| 423 | + $first = false; | |
| 424 | + } else | |
| 425 | + $out = 'Authorization: OAuth'; | |
| 426 | + | |
| 427 | + $total = array(); | |
| 428 | + foreach ($this->parameters as $k => $v) { | |
| 429 | + if (substr($k, 0, 5) != "oauth") continue; | |
| 430 | + if (is_array($v)) { | |
| 431 | + throw new OAuthException('Arrays not supported in headers'); | |
| 432 | + } | |
| 433 | + $out .= ($first) ? ' ' : ','; | |
| 434 | + $out .= OAuthUtil::urlencode_rfc3986($k) . | |
| 435 | + '="' . | |
| 436 | + OAuthUtil::urlencode_rfc3986($v) . | |
| 437 | + '"'; | |
| 438 | + $first = false; | |
| 439 | + } | |
| 440 | + return $out; | |
| 441 | + } | |
| 442 | + | |
| 443 | + public function __toString() { | |
| 444 | + return $this->to_url(); | |
| 445 | + } | |
| 446 | + | |
| 447 | + | |
| 448 | + public function sign_request($signature_method, $consumer, $token) { | |
| 449 | + $this->set_parameter( | |
| 450 | + "oauth_signature_method", | |
| 451 | + $signature_method->get_name(), | |
| 452 | + false | |
| 453 | + ); | |
| 454 | + $signature = $this->build_signature($signature_method, $consumer, $token); | |
| 455 | + $this->set_parameter("oauth_signature", $signature, false); | |
| 456 | + } | |
| 457 | + | |
| 458 | + public function build_signature($signature_method, $consumer, $token) { | |
| 459 | + $signature = $signature_method->build_signature($this, $consumer, $token); | |
| 460 | + return $signature; | |
| 461 | + } | |
| 462 | + | |
| 463 | + /** | |
| 464 | + * util function: current timestamp | |
| 465 | + */ | |
| 466 | + private static function generate_timestamp() { | |
| 467 | + return time(); | |
| 468 | + } | |
| 469 | + | |
| 470 | + /** | |
| 471 | + * util function: current nonce | |
| 472 | + */ | |
| 473 | + private static function generate_nonce() { | |
| 474 | + $mt = microtime(); | |
| 475 | + $rand = mt_rand(); | |
| 476 | + | |
| 477 | + return md5($mt . $rand); // md5s look nicer than numbers | |
| 478 | + } | |
| 479 | +} | |
| 480 | + | |
| 481 | +class OAuthServer { | |
| 482 | + protected $timestamp_threshold = 300; // in seconds, five minutes | |
| 483 | + protected $version = '1.0'; // hi blaine | |
| 484 | + protected $signature_methods = array(); | |
| 485 | + | |
| 486 | + protected $data_store; | |
| 487 | + | |
| 488 | + function __construct($data_store) { | |
| 489 | + $this->data_store = $data_store; | |
| 490 | + } | |
| 491 | + | |
| 492 | + public function add_signature_method($signature_method) { | |
| 493 | + $this->signature_methods[$signature_method->get_name()] = | |
| 494 | + $signature_method; | |
| 495 | + } | |
| 496 | + | |
| 497 | + // high level functions | |
| 498 | + | |
| 499 | + /** | |
| 500 | + * process a request_token request | |
| 501 | + * returns the request token on success | |
| 502 | + */ | |
| 503 | + public function fetch_request_token(&$request) { | |
| 504 | + $this->get_version($request); | |
| 505 | + | |
| 506 | + $consumer = $this->get_consumer($request); | |
| 507 | + | |
| 508 | + // no token required for the initial token request | |
| 509 | + $token = NULL; | |
| 510 | + | |
| 511 | + $this->check_signature($request, $consumer, $token); | |
| 512 | + | |
| 513 | + // Rev A change | |
| 514 | + $callback = $request->get_parameter('oauth_callback'); | |
| 515 | + $new_token = $this->data_store->new_request_token($consumer, $callback); | |
| 516 | + | |
| 517 | + return $new_token; | |
| 518 | + } | |
| 519 | + | |
| 520 | + /** | |
| 521 | + * process an access_token request | |
| 522 | + * returns the access token on success | |
| 523 | + */ | |
| 524 | + public function fetch_access_token(&$request) { | |
| 525 | + $this->get_version($request); | |
| 526 | + | |
| 527 | + $consumer = $this->get_consumer($request); | |
| 528 | + | |
| 529 | + // requires authorized request token | |
| 530 | + $token = $this->get_token($request, $consumer, "request"); | |
| 531 | + | |
| 532 | + $this->check_signature($request, $consumer, $token); | |
| 533 | + | |
| 534 | + // Rev A change | |
| 535 | + $verifier = $request->get_parameter('oauth_verifier'); | |
| 536 | + $new_token = $this->data_store->new_access_token($token, $consumer, $verifier); | |
| 537 | + | |
| 538 | + return $new_token; | |
| 539 | + } | |
| 540 | + | |
| 541 | + /** | |
| 542 | + * verify an api call, checks all the parameters | |
| 543 | + */ | |
| 544 | + public function verify_request(&$request) { | |
| 545 | + $this->get_version($request); | |
| 546 | + $consumer = $this->get_consumer($request); | |
| 547 | + $token = $this->get_token($request, $consumer, "access"); | |
| 548 | + $this->check_signature($request, $consumer, $token); | |
| 549 | + return array($consumer, $token); | |
| 550 | + } | |
| 551 | + | |
| 552 | + // Internals from here | |
| 553 | + /** | |
| 554 | + * version 1 | |
| 555 | + */ | |
| 556 | + private function get_version(&$request) { | |
| 557 | + $version = $request->get_parameter("oauth_version"); | |
| 558 | + if (!$version) { | |
| 559 | + // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. | |
| 560 | + // Chapter 7.0 ("Accessing Protected Ressources") | |
| 561 | + $version = '1.0'; | |
| 562 | + } | |
| 563 | + if ($version !== $this->version) { | |
| 564 | + throw new OAuthException("OAuth version '$version' not supported"); | |
| 565 | + } | |
| 566 | + return $version; | |
| 567 | + } | |
| 568 | + | |
| 569 | + /** | |
| 570 | + * figure out the signature with some defaults | |
| 571 | + */ | |
| 572 | + private function get_signature_method(&$request) { | |
| 573 | + $signature_method = | |
| 574 | + @$request->get_parameter("oauth_signature_method"); | |
| 575 | + | |
| 576 | + if (!$signature_method) { | |
| 577 | + // According to chapter 7 ("Accessing Protected Ressources") the signature-method | |
| 578 | + // parameter is required, and we can't just fallback to PLAINTEXT | |
| 579 | + throw new OAuthException('No signature method parameter. This parameter is required'); | |
| 580 | + } | |
| 581 | + | |
| 582 | + if (!in_array($signature_method, | |
| 583 | + array_keys($this->signature_methods))) { | |
| 584 | + throw new OAuthException( | |
| 585 | + "Signature method '$signature_method' not supported " . | |
| 586 | + "try one of the following: " . | |
| 587 | + implode(", ", array_keys($this->signature_methods)) | |
| 588 | + ); | |
| 589 | + } | |
| 590 | + return $this->signature_methods[$signature_method]; | |
| 591 | + } | |
| 592 | + | |
| 593 | + /** | |
| 594 | + * try to find the consumer for the provided request's consumer key | |
| 595 | + */ | |
| 596 | + private function get_consumer(&$request) { | |
| 597 | + $consumer_key = @$request->get_parameter("oauth_consumer_key"); | |
| 598 | + if (!$consumer_key) { | |
| 599 | + throw new OAuthException("Invalid consumer key"); | |
| 600 | + } | |
| 601 | + | |
| 602 | + $consumer = $this->data_store->lookup_consumer($consumer_key); | |
| 603 | + if (!$consumer) { | |
| 604 | + throw new OAuthException("Invalid consumer"); | |
| 605 | + } | |
| 606 | + | |
| 607 | + return $consumer; | |
| 608 | + } | |
| 609 | + | |
| 610 | + /** | |
| 611 | + * try to find the token for the provided request's token key | |
| 612 | + */ | |
| 613 | + private function get_token(&$request, $consumer, $token_type="access") { | |
| 614 | + $token_field = @$request->get_parameter('oauth_token'); | |
| 615 | + $token = $this->data_store->lookup_token( | |
| 616 | + $consumer, $token_type, $token_field | |
| 617 | + ); | |
| 618 | + if (!$token) { | |
| 619 | + throw new OAuthException("Invalid $token_type token: $token_field"); | |
| 620 | + } | |
| 621 | + return $token; | |
| 622 | + } | |
| 623 | + | |
| 624 | + /** | |
| 625 | + * all-in-one function to check the signature on a request | |
| 626 | + * should guess the signature method appropriately | |
| 627 | + */ | |
| 628 | + private function check_signature(&$request, $consumer, $token) { | |
| 629 | + // this should probably be in a different method | |
| 630 | + $timestamp = @$request->get_parameter('oauth_timestamp'); | |
| 631 | + $nonce = @$request->get_parameter('oauth_nonce'); | |
| 632 | + | |
| 633 | + $this->check_timestamp($timestamp); | |
| 634 | + $this->check_nonce($consumer, $token, $nonce, $timestamp); | |
| 635 | + | |
| 636 | + $signature_method = $this->get_signature_method($request); | |
| 637 | + | |
| 638 | + $signature = $request->get_parameter('oauth_signature'); | |
| 639 | + $valid_sig = $signature_method->check_signature( | |
| 640 | + $request, | |
| 641 | + $consumer, | |
| 642 | + $token, | |
| 643 | + $signature | |
| 644 | + ); | |
| 645 | + | |
| 646 | + if (!$valid_sig) { | |
| 647 | + throw new OAuthException("Invalid signature"); | |
| 648 | + } | |
| 649 | + } | |
| 650 | + | |
| 651 | + /** | |
| 652 | + * check that the timestamp is new enough | |
| 653 | + */ | |
| 654 | + private function check_timestamp($timestamp) { | |
| 655 | + if( ! $timestamp ) | |
| 656 | + throw new OAuthException( | |
| 657 | + 'Missing timestamp parameter. The parameter is required' | |
| 658 | + ); | |
| 659 | + | |
| 660 | + // verify that timestamp is recentish | |
| 661 | + $now = time(); | |
| 662 | + if (abs($now - $timestamp) > $this->timestamp_threshold) { | |
| 663 | + throw new OAuthException( | |
| 664 | + "Expired timestamp, yours $timestamp, ours $now" | |
| 665 | + ); | |
| 666 | + } | |
| 667 | + } | |
| 668 | + | |
| 669 | + /** | |
| 670 | + * check that the nonce is not repeated | |
| 671 | + */ | |
| 672 | + private function check_nonce($consumer, $token, $nonce, $timestamp) { | |
| 673 | + if( ! $nonce ) | |
| 674 | + throw new OAuthException( | |
| 675 | + 'Missing nonce parameter. The parameter is required' | |
| 676 | + ); | |
| 677 | + | |
| 678 | + // verify that the nonce is uniqueish | |
| 679 | + $found = $this->data_store->lookup_nonce( | |
| 680 | + $consumer, | |
| 681 | + $token, | |
| 682 | + $nonce, | |
| 683 | + $timestamp | |
| 684 | + ); | |
| 685 | + if ($found) { | |
| 686 | + throw new OAuthException("Nonce already used: $nonce"); | |
| 687 | + } | |
| 688 | + } | |
| 689 | + | |
| 690 | +} | |
| 691 | + | |
| 692 | +class OAuthDataStore { | |
| 693 | + function lookup_consumer($consumer_key) { | |
| 694 | + // implement me | |
| 695 | + } | |
| 696 | + | |
| 697 | + function lookup_token($consumer, $token_type, $token) { | |
| 698 | + // implement me | |
| 699 | + } | |
| 700 | + | |
| 701 | + function lookup_nonce($consumer, $token, $nonce, $timestamp) { | |
| 702 | + // implement me | |
| 703 | + } | |
| 704 | + | |
| 705 | + function new_request_token($consumer, $callback = null) { | |
| 706 | + // return a new token attached to this consumer | |
| 707 | + } | |
| 708 | + | |
| 709 | + function new_access_token($token, $consumer, $verifier = null) { | |
| 710 | + // return a new access token attached to this consumer | |
| 711 | + // for the user associated with this token if the request token | |
| 712 | + // is authorized | |
| 713 | + // should also invalidate the request token | |
| 714 | + } | |
| 715 | + | |
| 716 | +} | |
| 717 | + | |
| 718 | +class OAuthUtil { | |
| 719 | + public static function urlencode_rfc3986($input) { | |
| 720 | + if (is_array($input)) { | |
| 721 | + return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); | |
| 722 | + } else if (is_scalar($input)) { | |
| 723 | + return str_replace( | |
| 724 | + '+', | |
| 725 | + ' ', | |
| 726 | + str_replace('%7E', '~', rawurlencode($input)) | |
| 727 | + ); | |
| 728 | + } else { | |
| 729 | + return ''; | |
| 730 | + } | |
| 731 | +} | |
| 732 | + | |
| 733 | + | |
| 734 | + // This decode function isn't taking into consideration the above | |
| 735 | + // modifications to the encoding process. However, this method doesn't | |
| 736 | + // seem to be used anywhere so leaving it as is. | |
| 737 | + public static function urldecode_rfc3986($string) { | |
| 738 | + return urldecode($string); | |
| 739 | + } | |
| 740 | + | |
| 741 | + // Utility function for turning the Authorization: header into | |
| 742 | + // parameters, has to do some unescaping | |
| 743 | + // Can filter out any non-oauth parameters if needed (default behaviour) | |
| 744 | + public static function split_header($header, $only_allow_oauth_parameters = true) { | |
| 745 | + $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; | |
| 746 | + $offset = 0; | |
| 747 | + $params = array(); | |
| 748 | + while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { | |
| 749 | + $match = $matches[0]; | |
| 750 | + $header_name = $matches[2][0]; | |
| 751 | + $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; | |
| 752 | + if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) { | |
| 753 | + $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content); | |
| 754 | + } | |
| 755 | + $offset = $match[1] + strlen($match[0]); | |
| 756 | + } | |
| 757 | + | |
| 758 | + if (isset($params['realm'])) { | |
| 759 | + unset($params['realm']); | |
| 760 | + } | |
| 761 | + | |
| 762 | + return $params; | |
| 763 | + } | |
| 764 | + | |
| 765 | + // helper to try to sort out headers for people who aren't running apache | |
| 766 | + public static function get_headers() { | |
| 767 | + if (function_exists('apache_request_headers')) { | |
| 768 | + // we need this to get the actual Authorization: header | |
| 769 | + // because apache tends to tell us it doesn't exist | |
| 770 | + $headers = apache_request_headers(); | |
| 771 | + | |
| 772 | + // sanitize the output of apache_request_headers because | |
| 773 | + // we always want the keys to be Cased-Like-This and arh() | |
| 774 | + // returns the headers in the same case as they are in the | |
| 775 | + // request | |
| 776 | + $out = array(); | |
| 777 | + foreach( $headers AS $key => $value ) { | |
| 778 | + $key = str_replace( | |
| 779 | + " ", | |
| 780 | + "-", | |
| 781 | + ucwords(strtolower(str_replace("-", " ", $key))) | |
| 782 | + ); | |
| 783 | + $out[$key] = $value; | |
| 784 | + } | |
| 785 | + } else { | |
| 786 | + // otherwise we don't have apache and are just going to have to hope | |
| 787 | + // that $_SERVER actually contains what we need | |
| 788 | + $out = array(); | |
| 789 | + if( isset($_SERVER['CONTENT_TYPE']) ) | |
| 790 | + $out['Content-Type'] = $_SERVER['CONTENT_TYPE']; | |
| 791 | + if( isset($_ENV['CONTENT_TYPE']) ) | |
| 792 | + $out['Content-Type'] = $_ENV['CONTENT_TYPE']; | |
| 793 | + | |
| 794 | + foreach ($_SERVER as $key => $value) { | |
| 795 | + if (substr($key, 0, 5) == "HTTP_") { | |
| 796 | + // this is chaos, basically it is just there to capitalize the first | |
| 797 | + // letter of every word that is not an initial HTTP and strip HTTP | |
| 798 | + // code from przemek | |
| 799 | + $key = str_replace( | |
| 800 | + " ", | |
| 801 | + "-", | |
| 802 | + ucwords(strtolower(str_replace("_", " ", substr($key, 5)))) | |
| 803 | + ); | |
| 804 | + $out[$key] = $value; | |
| 805 | + } | |
| 806 | + } | |
| 807 | + } | |
| 808 | + return $out; | |
| 809 | + } | |
| 810 | + | |
| 811 | + // This function takes a input like a=b&a=c&d=e and returns the parsed | |
| 812 | + // parameters like this | |
| 813 | + // array('a' => array('b','c'), 'd' => 'e') | |
| 814 | + public static function parse_parameters( $input ) { | |
| 815 | + if (!isset($input) || !$input) return array(); | |
| 816 | + | |
| 817 | + $pairs = explode('&', $input); | |
| 818 | + | |
| 819 | + $parsed_parameters = array(); | |
| 820 | + foreach ($pairs as $pair) { | |
| 821 | + $split = explode('=', $pair, 2); | |
| 822 | + $parameter = OAuthUtil::urldecode_rfc3986($split[0]); | |
| 823 | + $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : ''; | |
| 824 | + | |
| 825 | + if (isset($parsed_parameters[$parameter])) { | |
| 826 | + // We have already recieved parameter(s) with this name, so add to the list | |
| 827 | + // of parameters with this name | |
| 828 | + | |
| 829 | + if (is_scalar($parsed_parameters[$parameter])) { | |
| 830 | + // This is the first duplicate, so transform scalar (string) into an array | |
| 831 | + // so we can add the duplicates | |
| 832 | + $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); | |
| 833 | + } | |
| 834 | + | |
| 835 | + $parsed_parameters[$parameter][] = $value; | |
| 836 | + } else { | |
| 837 | + $parsed_parameters[$parameter] = $value; | |
| 838 | + } | |
| 839 | + } | |
| 840 | + return $parsed_parameters; | |
| 841 | + } | |
| 842 | + | |
| 843 | + public static function build_http_query($params) { | |
| 844 | + if (!$params) return ''; | |
| 845 | + | |
| 846 | + // Urlencode both keys and values | |
| 847 | + $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); | |
| 848 | + $values = OAuthUtil::urlencode_rfc3986(array_values($params)); | |
| 849 | + $params = array_combine($keys, $values); | |
| 850 | + | |
| 851 | + // Parameters are sorted by name, using lexicographical byte value ordering. | |
| 852 | + // Ref: Spec: 9.1.1 (1) | |
| 853 | + uksort($params, 'strcmp'); | |
| 854 | + | |
| 855 | + $pairs = array(); | |
| 856 | + foreach ($params as $parameter => $value) { | |
| 857 | + if (is_array($value)) { | |
| 858 | + // If two or more parameters share the same name, they are sorted by their value | |
| 859 | + // Ref: Spec: 9.1.1 (1) | |
| 860 | + natsort($value); | |
| 861 | + foreach ($value as $duplicate_value) { | |
| 862 | + $pairs[] = $parameter . '=' . $duplicate_value; | |
| 863 | + } | |
| 864 | + } else { | |
| 865 | + $pairs[] = $parameter . '=' . $value; | |
| 866 | + } | |
| 867 | + } | |
| 868 | + // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) | |
| 869 | + // Each name-value pair is separated by an '&' character (ASCII code 38) | |
| 870 | + return implode('&', $pairs); | |
| 871 | + } | |
| 872 | +} | |
| 873 | + | |
| 874 | +?> | ... | ... |
| ... | ... | @@ -0,0 +1,245 @@ |
| 1 | +<?php | |
| 2 | + | |
| 3 | +/* | |
| 4 | + * Abraham Williams (abraham@abrah.am) http://abrah.am | |
| 5 | + * | |
| 6 | + * The first PHP Library to support OAuth for Twitter's REST API. | |
| 7 | + */ | |
| 8 | + | |
| 9 | +/* Load OAuth lib. You can find it at http://oauth.net */ | |
| 10 | +require_once('OAuth.php'); | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * Twitter OAuth class | |
| 14 | + */ | |
| 15 | +class TwitterOAuth { | |
| 16 | + /* Contains the last HTTP status code returned. */ | |
| 17 | + public $http_code; | |
| 18 | + /* Contains the last API call. */ | |
| 19 | + public $url; | |
| 20 | + /* Set up the API root URL. */ | |
| 21 | + public $host = "https://api.twitter.com/1/"; | |
| 22 | + /* Set timeout default. */ | |
| 23 | + public $timeout = 30; | |
| 24 | + /* Set connect timeout. */ | |
| 25 | + public $connecttimeout = 30; | |
| 26 | + /* Verify SSL Cert. */ | |
| 27 | + public $ssl_verifypeer = FALSE; | |
| 28 | + /* Respons format. */ | |
| 29 | + public $format = 'json'; | |
| 30 | + /* Decode returned json data. */ | |
| 31 | + public $decode_json = TRUE; | |
| 32 | + /* Contains the last HTTP headers returned. */ | |
| 33 | + public $http_info; | |
| 34 | + /* Set the useragnet. */ | |
| 35 | + public $useragent = 'TwitterOAuth v0.2.0-beta2'; | |
| 36 | + /* Immediately retry the API call if the response was not successful. */ | |
| 37 | + //public $retry = TRUE; | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * Set API URLS | |
| 44 | + */ | |
| 45 | + function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; } | |
| 46 | + function authenticateURL() { return 'https://twitter.com/oauth/authenticate'; } | |
| 47 | + function authorizeURL() { return 'https://twitter.com/oauth/authorize'; } | |
| 48 | + function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; } | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Debug helpers | |
| 52 | + */ | |
| 53 | + function lastStatusCode() { return $this->http_status; } | |
| 54 | + function lastAPICall() { return $this->last_api_call; } | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * construct TwitterOAuth object | |
| 58 | + */ | |
| 59 | + function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) { | |
| 60 | + $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1(); | |
| 61 | + $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); | |
| 62 | + if (!empty($oauth_token) && !empty($oauth_token_secret)) { | |
| 63 | + $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret); | |
| 64 | + } else { | |
| 65 | + $this->token = NULL; | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * Get a request_token from Twitter | |
| 72 | + * | |
| 73 | + * @returns a key/value array containing oauth_token and oauth_token_secret | |
| 74 | + */ | |
| 75 | + function getRequestToken($oauth_callback = NULL) { | |
| 76 | + $parameters = array(); | |
| 77 | + if (!empty($oauth_callback)) { | |
| 78 | + $parameters['oauth_callback'] = $oauth_callback; | |
| 79 | + } | |
| 80 | + $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters); | |
| 81 | + $token = OAuthUtil::parse_parameters($request); | |
| 82 | + $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); | |
| 83 | + return $token; | |
| 84 | + } | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * Get the authorize URL | |
| 88 | + * | |
| 89 | + * @returns a string | |
| 90 | + */ | |
| 91 | + function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) { | |
| 92 | + if (is_array($token)) { | |
| 93 | + $token = $token['oauth_token']; | |
| 94 | + } | |
| 95 | + if (empty($sign_in_with_twitter)) { | |
| 96 | + return $this->authorizeURL() . "?oauth_token={$token}"; | |
| 97 | + } else { | |
| 98 | + return $this->authenticateURL() . "?oauth_token={$token}"; | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Exchange request token and secret for an access token and | |
| 104 | + * secret, to sign API calls. | |
| 105 | + * | |
| 106 | + * @returns array("oauth_token" => "the-access-token", | |
| 107 | + * "oauth_token_secret" => "the-access-secret", | |
| 108 | + * "user_id" => "9436992", | |
| 109 | + * "screen_name" => "abraham") | |
| 110 | + */ | |
| 111 | + function getAccessToken($oauth_verifier = FALSE) { | |
| 112 | + $parameters = array(); | |
| 113 | + if (!empty($oauth_verifier)) { | |
| 114 | + $parameters['oauth_verifier'] = $oauth_verifier; | |
| 115 | + } | |
| 116 | + $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters); | |
| 117 | + $token = OAuthUtil::parse_parameters($request); | |
| 118 | + $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); | |
| 119 | + return $token; | |
| 120 | + } | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * One time exchange of username and password for access token and secret. | |
| 124 | + * | |
| 125 | + * @returns array("oauth_token" => "the-access-token", | |
| 126 | + * "oauth_token_secret" => "the-access-secret", | |
| 127 | + * "user_id" => "9436992", | |
| 128 | + * "screen_name" => "abraham", | |
| 129 | + * "x_auth_expires" => "0") | |
| 130 | + */ | |
| 131 | + function getXAuthToken($username, $password) { | |
| 132 | + $parameters = array(); | |
| 133 | + $parameters['x_auth_username'] = $username; | |
| 134 | + $parameters['x_auth_password'] = $password; | |
| 135 | + $parameters['x_auth_mode'] = 'client_auth'; | |
| 136 | + $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters); | |
| 137 | + $token = OAuthUtil::parse_parameters($request); | |
| 138 | + $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); | |
| 139 | + return $token; | |
| 140 | + } | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * GET wrapper for oAuthRequest. | |
| 144 | + */ | |
| 145 | + function get($url, $parameters = array()) { | |
| 146 | + $response = $this->oAuthRequest($url, 'GET', $parameters); | |
| 147 | + if ($this->format === 'json' && $this->decode_json) { | |
| 148 | + return json_decode($response); | |
| 149 | + } | |
| 150 | + return $response; | |
| 151 | + } | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * POST wrapper for oAuthRequest. | |
| 155 | + */ | |
| 156 | + function post($url, $parameters = array()) { | |
| 157 | + $response = $this->oAuthRequest($url, 'POST', $parameters); | |
| 158 | + if ($this->format === 'json' && $this->decode_json) { | |
| 159 | + return json_decode($response); | |
| 160 | + } | |
| 161 | + return $response; | |
| 162 | + } | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * DELETE wrapper for oAuthReqeust. | |
| 166 | + */ | |
| 167 | + function delete($url, $parameters = array()) { | |
| 168 | + $response = $this->oAuthRequest($url, 'DELETE', $parameters); | |
| 169 | + if ($this->format === 'json' && $this->decode_json) { | |
| 170 | + return json_decode($response); | |
| 171 | + } | |
| 172 | + return $response; | |
| 173 | + } | |
| 174 | + | |
| 175 | + /** | |
| 176 | + * Format and sign an OAuth / API request | |
| 177 | + */ | |
| 178 | + function oAuthRequest($url, $method, $parameters) { | |
| 179 | + if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) { | |
| 180 | + $url = "{$this->host}{$url}.{$this->format}"; | |
| 181 | + } | |
| 182 | + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters); | |
| 183 | + $request->sign_request($this->sha1_method, $this->consumer, $this->token); | |
| 184 | + switch ($method) { | |
| 185 | + case 'GET': | |
| 186 | + return $this->http($request->to_url(), 'GET'); | |
| 187 | + default: | |
| 188 | + return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata()); | |
| 189 | + } | |
| 190 | + } | |
| 191 | + | |
| 192 | + /** | |
| 193 | + * Make an HTTP request | |
| 194 | + * | |
| 195 | + * @return API results | |
| 196 | + */ | |
| 197 | + function http($url, $method, $postfields = NULL) { | |
| 198 | + $this->http_info = array(); | |
| 199 | + $ci = curl_init(); | |
| 200 | + /* Curl settings */ | |
| 201 | + curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent); | |
| 202 | + curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout); | |
| 203 | + curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout); | |
| 204 | + curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE); | |
| 205 | + curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:')); | |
| 206 | + curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer); | |
| 207 | + curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader')); | |
| 208 | + curl_setopt($ci, CURLOPT_HEADER, FALSE); | |
| 209 | + | |
| 210 | + switch ($method) { | |
| 211 | + case 'POST': | |
| 212 | + curl_setopt($ci, CURLOPT_POST, TRUE); | |
| 213 | + if (!empty($postfields)) { | |
| 214 | + curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); | |
| 215 | + } | |
| 216 | + break; | |
| 217 | + case 'DELETE': | |
| 218 | + curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE'); | |
| 219 | + if (!empty($postfields)) { | |
| 220 | + $url = "{$url}?{$postfields}"; | |
| 221 | + } | |
| 222 | + } | |
| 223 | + | |
| 224 | + curl_setopt($ci, CURLOPT_URL, $url); | |
| 225 | + $response = curl_exec($ci); | |
| 226 | + $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE); | |
| 227 | + $this->http_info = array_merge($this->http_info, curl_getinfo($ci)); | |
| 228 | + $this->url = $url; | |
| 229 | + curl_close ($ci); | |
| 230 | + return $response; | |
| 231 | + } | |
| 232 | + | |
| 233 | + /** | |
| 234 | + * Get the header info to store. | |
| 235 | + */ | |
| 236 | + function getHeader($ch, $header) { | |
| 237 | + $i = strpos($header, ':'); | |
| 238 | + if (!empty($i)) { | |
| 239 | + $key = str_replace('-', '_', strtolower(substr($header, 0, $i))); | |
| 240 | + $value = trim(substr($header, $i + 2)); | |
| 241 | + $this->http_header[$key] = $value; | |
| 242 | + } | |
| 243 | + return strlen($header); | |
| 244 | + } | |
| 245 | +} | ... | ... |
testainstal.php
| ... | ... | @@ -115,7 +115,8 @@ $tabelas = array( |
| 115 | 115 | "i3geoadmin_grupos"=>"it,es,en,desc_grupo,id_grupo,nome_grupo", |
| 116 | 116 | "i3geoadmin_subgrupos"=>"it,es,en,desc_subgrupo,id_subgrupo,nome_subgrupo", |
| 117 | 117 | "i3geoadmin_temas"=>"it,es,en,kmz_tema,nacessos,id_tema,kml_tema,ogc_tema,download_tema,tags_tema,tipoa_tema,link_tema,desc_tema,nome_tema,codigo_tema", |
| 118 | - "i3geoadmin_menus"=>"it,es,en,publicado_menu,perfil_menu,aberto,desc_menu,id_menu,nome_menu" | |
| 118 | + "i3geoadmin_menus"=>"it,es,en,publicado_menu,perfil_menu,aberto,desc_menu,id_menu,nome_menu", | |
| 119 | + "i3geoadmin_comentarios"=>"comentario,data,openidnome,openidimagem,openidservico,openidusuario,openidurl,id_tema" | |
| 119 | 120 | ); |
| 120 | 121 | include_once("admin/php/conexao.php"); |
| 121 | 122 | foreach(array_keys($tabelas) as $tabela) | ... | ... |