Merge branch '1.11.x' of https://github.com/chamilo/chamilo-lms into 1.11.x

pull/2731/head
Alex Aragón 7 years ago
commit 05cb0c85b9
  1. 2
      main/attendance/attendance_controller.php
  2. 2
      main/attendance/attendance_sheet.php
  3. 1
      main/gradebook/index.php
  4. 14
      main/inc/ajax/agenda.ajax.php
  5. 12
      main/inc/lib/agenda.lib.php
  6. 8
      main/inc/lib/attendance.lib.php
  7. 50
      main/inc/lib/lp_item.lib.php
  8. 2
      main/inc/lib/template.lib.php
  9. 7
      main/inc/lib/tracking.lib.php
  10. 12
      main/lang/brazilian/trad4all.inc.php
  11. 18
      main/lang/galician/trad4all.inc.php
  12. 2
      main/lang/polish/trad4all.inc.php
  13. 2
      main/lang/tagalog/trad4all.inc.php
  14. 6
      main/lp/learnpath.class.php
  15. 12
      main/survey/reporting.php
  16. 257
      main/survey/surveyUtil.class.php
  17. 57
      main/tracking/courseLog.php
  18. 38
      plugin/ims_lti/Entity/ImsLtiTool.php
  19. 81
      plugin/ims_lti/ImsLtiPlugin.php
  20. 12
      plugin/ims_lti/README.md
  21. 36
      plugin/ims_lti/configure.php
  22. 35
      plugin/ims_lti/create.php
  23. 16
      plugin/ims_lti/edit.php
  24. 54
      plugin/ims_lti/form.php
  25. 2
      plugin/ims_lti/lang/english.php
  26. 2
      plugin/ims_lti/lang/spanish.php
  27. 6
      plugin/ims_lti/src/Form/FrmAdd.php
  28. 6
      plugin/ims_lti/src/Form/FrmEdit.php
  29. 6
      plugin/ims_lti/start.php
  30. 42
      plugin/ims_lti/vendor/oauth1/.gitignore
  31. 44
      plugin/ims_lti/vendor/oauth1/CHANGELOG.md
  32. 22
      plugin/ims_lti/vendor/oauth1/LICENSE.txt
  33. 6
      plugin/ims_lti/vendor/oauth1/README.md
  34. 16
      plugin/ims_lti/vendor/oauth1/code/OAuthConsumer.php
  35. 27
      plugin/ims_lti/vendor/oauth1/code/OAuthDataStore.php
  36. 7
      plugin/ims_lti/vendor/oauth1/code/OAuthException.php
  37. 260
      plugin/ims_lti/vendor/oauth1/code/OAuthRequest.php
  38. 223
      plugin/ims_lti/vendor/oauth1/code/OAuthServer.php
  39. 55
      plugin/ims_lti/vendor/oauth1/code/OAuthSignatureMethod.php
  40. 30
      plugin/ims_lti/vendor/oauth1/code/OAuthSignatureMethod_HMAC_SHA1.php
  41. 34
      plugin/ims_lti/vendor/oauth1/code/OAuthSignatureMethod_PLAINTEXT.php
  42. 69
      plugin/ims_lti/vendor/oauth1/code/OAuthSignatureMethod_RSA_SHA1.php
  43. 13
      plugin/ims_lti/vendor/oauth1/code/OAuthTests.xml
  44. 31
      plugin/ims_lti/vendor/oauth1/code/OAuthToken.php
  45. 153
      plugin/ims_lti/vendor/oauth1/code/OAuthUtil.php
  46. 106
      plugin/ims_lti/vendor/oauth1/code/OAuth_TestServer.php
  47. 30
      plugin/ims_lti/vendor/oauth1/composer.json
  48. 20
      plugin/ims_lti/vendor/oauth1/composer.lock
  49. 73
      plugin/ims_lti/vendor/oauth1/doc/design.md
  50. 74
      plugin/ims_lti/vendor/oauth1/example/SimpleOAuthDataStore.php
  51. 14
      plugin/ims_lti/vendor/oauth1/example/access_token.php
  52. 133
      plugin/ims_lti/vendor/oauth1/example/client.php
  53. 26
      plugin/ims_lti/vendor/oauth1/example/common.inc.php
  54. 21
      plugin/ims_lti/vendor/oauth1/example/echo_api.php
  55. 108
      plugin/ims_lti/vendor/oauth1/example/index.php
  56. 14
      plugin/ims_lti/vendor/oauth1/example/request_token.php
  57. 5
      plugin/ims_lti/vendor/oauth1/init.php
  58. 12
      plugin/ims_lti/vendor/oauth1/tests/Mock_OAuthBaseStringRequest.php
  59. 57
      plugin/ims_lti/vendor/oauth1/tests/Mock_OAuthDataStore.php
  60. 47
      plugin/ims_lti/vendor/oauth1/tests/Mock_OAuthSignatureMethod_RSA_SHA1.php
  61. 10
      plugin/ims_lti/vendor/oauth1/tests/OAuthConsumerTest.php
  62. 329
      plugin/ims_lti/vendor/oauth1/tests/OAuthRequestTest.php
  63. 225
      plugin/ims_lti/vendor/oauth1/tests/OAuthServerTest.php
  64. 60
      plugin/ims_lti/vendor/oauth1/tests/OAuthSignatureMethodHmacSha1Test.php
  65. 79
      plugin/ims_lti/vendor/oauth1/tests/OAuthSignatureMethodPlaintextTest.php
  66. 43
      plugin/ims_lti/vendor/oauth1/tests/OAuthSignatureMethodRsaSha1Test.php
  67. 20
      plugin/ims_lti/vendor/oauth1/tests/OAuthTokenTest.php
  68. 151
      plugin/ims_lti/vendor/oauth1/tests/OAuthUtilTest.php
  69. 60
      plugin/ims_lti/vendor/oauth1/tests/common.php
  70. 4
      plugin/ims_lti/view/add.tpl
  71. 84
      plugin/ims_lti/view/admin.tpl
  72. 2
      plugin/ims_lti/view/start.tpl

@ -303,7 +303,7 @@ class AttendanceController
$isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
api_get_user_id(),
api_get_course_info()
);
) || api_is_drh();
if ($edit == true) {
if (api_is_allowed_to_edit(null, true) || $isDrhOfCourse) {

@ -16,7 +16,7 @@ api_protect_course_script(true);
$isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
api_get_user_id(),
api_get_course_info()
);
) || api_is_drh();
if (api_is_allowed_to_edit(null, true) ||
api_is_coach(api_get_session_id(), api_get_course_int_id()) ||

@ -786,7 +786,6 @@ if (isset($first_time) && $first_time == 1 && api_is_allowed_to_edit(null, true)
}
if (api_is_allowed_to_edit(null, true)) {
if (((empty($selectCat)) || (isset($_GET['cidReq']) && $_GET['cidReq'] !== '')) ||
(isset($_GET['isStudentView']) && $_GET['isStudentView'] == 'false')
) {

@ -19,6 +19,8 @@ if ($type == 'course') {
}
$agenda = new Agenda($type);
// get filtered type
$type = $agenda->getType();
switch ($action) {
case 'add_event':
@ -26,15 +28,17 @@ switch ($action) {
break;
}
$add_as_announcement = isset($_REQUEST['add_as_annonuncement']) ? $_REQUEST['add_as_annonuncement'] : null;
$comment = isset($_REQUEST['comment']) ? $_REQUEST['comment'] : null;
$title = isset($_REQUEST['title']) ? Security::remove_XSS($_REQUEST['title']) : null;
$content = isset($_REQUEST['content']) ? Security::remove_XSS($_REQUEST['content']) : null;
$comment = isset($_REQUEST['comment']) ? Security::remove_XSS($_REQUEST['comment']) : null;
$userToSend = isset($_REQUEST['users_to_send']) ? $_REQUEST['users_to_send'] : [];
echo $agenda->addEvent(
$_REQUEST['start'],
$_REQUEST['end'],
$_REQUEST['all_day'],
$_REQUEST['title'],
$_REQUEST['content'],
$title,
$content,
$userToSend,
$add_as_announcement,
null, //$parentEventId = null,
@ -54,8 +58,8 @@ switch ($action) {
$_REQUEST['start'],
$_REQUEST['end'],
$_REQUEST['all_day'],
$_REQUEST['title'],
$_REQUEST['content']
$title,
$content
);
break;
case 'delete_event':

@ -160,6 +160,18 @@ class Agenda
}
}
/**
* Returns the type previously set (and filtered) through setType
* If setType() was not called, then type defaults to "personal" as
* set in the class definition.
*/
public function getType()
{
if (isset($this->type)) {
return $this->type;
}
}
/**
* @param int $id
*/

@ -154,8 +154,9 @@ class Attendance
while ($attendance = Database::fetch_row($res)) {
$student_param = '';
if (api_is_drh() && $_GET['student_id']) {
$student_param = '&student_id='.intval($_GET['student_id']);
$studentRequestId = isset($_GET['student_id']) ? (int) $_GET['student_id'] : 0;
if (api_is_drh() && !empty($studentRequestId)) {
$student_param = '&student_id='.$studentRequestId;
}
$session_star = '';
@ -166,8 +167,7 @@ class Attendance
$isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
api_get_user_id(),
api_get_course_info()
);
) || api_is_drh();
if (api_is_allowed_to_edit(null, true) || $isDrhOfCourse) {
// Link to edit
$attendance[1] = '<a href="index.php?'.api_get_cidreq().'&action=attendance_sheet_list&attendance_id='.$attendance[0].$student_param.'">'.$attendance[1].'</a>'.$session_star;

@ -43,10 +43,10 @@ class LpItem
{
if ($in_c_id > 0 && $in_id > 0) {
$item_view_table = Database::get_course_table(TABLE_LP_ITEM);
$sql = "SELECT * FROM $item_view_table
WHERE
c_id=".intval($in_c_id)." AND
id=".intval($in_id);
$sql = "SELECT * FROM $item_view_table
WHERE
c_id=".intval($in_c_id)." AND
iid=".intval($in_id);
$res = Database::query($sql);
$data = Database::fetch_array($res);
@ -84,27 +84,27 @@ class LpItem
{
$table = Database::get_course_table(TABLE_LP_ITEM);
if ($this->c_id > 0 && $this->id > 0) {
$sql = "UPDATE $table SET
lp_id = '".intval($this->lp_id)."' ,
item_type = '".Database::escape_string($this->item_type)."' ,
ref = '".Database::escape_string($this->ref)."' ,
title = '".Database::escape_string($this->title)."' ,
description = '".Database::escape_string($this->description)."' ,
path = '".Database::escape_string($this->path)."' ,
min_score = '".Database::escape_string($this->min_score)."' ,
max_score = '".Database::escape_string($this->max_score)."' ,
mastery_score = '".Database::escape_string($this->mastery_score)."' ,
parent_item_id = '".Database::escape_string($this->parent_item_id)."' ,
previous_item_id = '".Database::escape_string($this->previous_item_id)."' ,
next_item_id = '".Database::escape_string($this->next_item_id)."' ,
display_order = '".Database::escape_string($this->display_order)."' ,
prerequisite = '".Database::escape_string($this->prerequisite)."' ,
parameters = '".Database::escape_string($this->parameters)."' ,
launch_data = '".Database::escape_string($this->launch_data)."' ,
max_time_allowed = '".Database::escape_string($this->max_time_allowed)."' ,
terms = '".Database::escape_string($this->terms)."' ,
search_did = '".Database::escape_string($this->search_did)."' ,
audio = '".Database::escape_string($this->audio)."'
$sql = "UPDATE $table SET
lp_id = '".intval($this->lp_id)."' ,
item_type = '".Database::escape_string($this->item_type)."' ,
ref = '".Database::escape_string($this->ref)."' ,
title = '".Database::escape_string($this->title)."' ,
description = '".Database::escape_string($this->description)."' ,
path = '".Database::escape_string($this->path)."' ,
min_score = '".Database::escape_string($this->min_score)."' ,
max_score = '".Database::escape_string($this->max_score)."' ,
mastery_score = '".Database::escape_string($this->mastery_score)."' ,
parent_item_id = '".Database::escape_string($this->parent_item_id)."' ,
previous_item_id = '".Database::escape_string($this->previous_item_id)."' ,
next_item_id = '".Database::escape_string($this->next_item_id)."' ,
display_order = '".Database::escape_string($this->display_order)."' ,
prerequisite = '".Database::escape_string($this->prerequisite)."' ,
parameters = '".Database::escape_string($this->parameters)."' ,
launch_data = '".Database::escape_string($this->launch_data)."' ,
max_time_allowed = '".Database::escape_string($this->max_time_allowed)."' ,
terms = '".Database::escape_string($this->terms)."' ,
search_did = '".Database::escape_string($this->search_did)."' ,
audio = '".Database::escape_string($this->audio)."'
WHERE c_id=".$this->c_id." AND id=".$this->id;
Database::query($sql);
}

@ -1916,7 +1916,9 @@ class Template
/**
* Get platform meta image tag (check meta_image_path setting, then use the logo).
*
* @param string $imageAlt The alt attribute for the image
*
* @return string The meta image HTML tag, or empty
*/
private function getMetaPortalImagePath($imageAlt = '')

@ -7448,8 +7448,9 @@ class TrackingCourseLog
$direction,
$includeInvitedUsers = false
) {
global $user_ids, $course_code, $export_csv, $csv_content, $session_id;
global $user_ids, $course_code, $export_csv, $session_id;
$csv_content = [];
$course_code = Database::escape_string($course_code);
$tbl_user = Database::get_main_table(TABLE_MAIN_USER);
$tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
@ -7696,6 +7697,10 @@ class TrackingCourseLog
$users[] = array_values($user_row);
}
if ($export_csv) {
Session::write('csv_content', $csv_content);
}
Session::erase('additional_user_profile_info');
Session::erase('extra_field_info');

@ -79,7 +79,7 @@ $HyperbolicArctangentArctanh = "Arco tangente hiperbólica: \t\t arctanh (x)";
$SessionDurationTitle = "Duração da sessão";
$ArctangentArctan = "Arctangent:\t\t\tarctan(x)";
$HyperbolicTangentTanh = "Tangente hiperbólica:\t\ttanh(x)";
$TangentTan = "Tangent:\t\t\ TTAN (x)";
$TangentTan = "Tangent:\t\t\tTAN (x)";
$CoachAndStudent = "Treinador e aluno";
$Serie = "Series";
$HyperbolicArccosineArccosh = "Arccosine hiperbólica:\t\tarccosh(x)";
@ -90,13 +90,13 @@ $TeacherTimeReport = "Professores relatório de tempo";
$HyperbolicArcsineArcsinh = "arcsine hiperbólica:\t\tarcsinh(x)";
$YourLanguageNotThereContactUs = "Não é possível encontrar o seu idioma na lista? Contacte-nos em info@chamilo.org contribuir como um tradutor.";
$ArcsineArcsin = "arcsine:\t\t\tarcsin(x)";
$HyperbolicSineSinh = "Seno hiperbólico:\t\ sinh(x)";
$HyperbolicSineSinh = "Seno hiperbólico:\t\tsinh(x)";
$SineSin = "Sine:\t\t\t\tsin(x)";
$PiNumberPi = "Número Pi:\t\t\tpi";
$ENumberE = "Número E:\t\t\te";
$LogarithmLog = "Logaritmo:\t\t\tlog(x)";
$NaturalLogarithmLn = "Logaritmo natural:\t\tln(x)";
$AbsoluteValueAbs = "Valor absoluto:\t\t\abas(x)";
$AbsoluteValueAbs = "Valor absoluto:\t\t\tabas(x)";
$SquareRootSqrt = "Raiz quadrada:\t\t\tsqrt(x)";
$ExponentiationCircumflex = "Exponenciação:\t\t\t^";
$DivisionSlash = "Divisão:\t\t\t/";
@ -2348,7 +2348,7 @@ $GroupDescription = "Descrição do grupo";
$GroupMembers = "Membros do grupo";
$EditGroup = "Editar este grupo";
$GroupSettingsModified = "Configurações do grupo modificado";
$GroupTooMuchMembers = "Número proposta excede max que você permitiu que (você pode modificá-lo abaixo) \ t \ t \ t \ composição tgroup não foi modificado.";
$GroupTooMuchMembers = "Número proposta excede max que você permitiu que (você pode modificá-lo abaixo) \t\t\t\t composição tgroup não foi modificado.";
$GroupTutor = "Tutor Grupo";
$GroupNoTutor = "(nenhum)";
$GroupNone = "(nenhum)";
@ -5934,7 +5934,7 @@ $ContactInformationHasBeenSent = "As informações de contato foram enviadas";
$EditExtraFieldOptions = "Editar opções de campos extra";
$ExerciseDescriptionLabel = "Descrição";
$UserInactivedSinceX = "Usuário inativo desde %s";
$ContactInformationDescription = "Prezado usuário, <br/>\ n <br/> Você está prestes a começar a usar um dos melhores de fonte aberta plataforma e-learning no mercado. Como muitos outros projetos de código aberto, este projecto é apoiado -se por uma grande comunidade de estudantes, professores, desenvolvedores e criadores de conteúdo que gostariam de promover melhor o projeto. <br/>\n <br/>\nAo saber um pouco mais sobre você, um dos nossos usuários mais importantes, quem vai gerir este chamilo de e-learning, que será capaz de deixar as pessoas sabem que o nosso software é usado e que você saiba quando nós organizamos eventos que possam ser relevantes para você. <br /> \ n <br /> \ nAo enchimento Desta forma, você aceita que a associação Chamilo ou seus membros possam enviar informações por e-mail sobre eventos importantes ou atualizações do software Chamilo ou comunidade. Isto irá ajudar a comunidade a crescer como uma entidade organizada, onde o fluxo de informações, com um respeito permanente de seu tempo e sua privacidade. <br /> \ n <br /> \ nPor favor nota que você é <b> não é necessário </ b> para preencher este formulário. Se você quiser permanecer anônimo, vamos perder a oportunidade de oferecer-lhe todos os privilégios de ser um administrador do portal registrado, mas nós vamos respeitar sua decisão. Basta deixar esta forma vazia e clique em \"Avançar\" <br/> <br/>.";
$ContactInformationDescription = "Prezado usuário, <br />\n <br /> Você está prestes a começar a usar um dos melhores de fonte aberta plataforma e-learning no mercado. Como muitos outros projetos de código aberto, este projecto é apoiado -se por uma grande comunidade de estudantes, professores, desenvolvedores e criadores de conteúdo que gostariam de promover melhor o projeto. <br />\n <br />\nAo saber um pouco mais sobre você, um dos nossos usuários mais importantes, quem vai gerir este chamilo de e-learning, que será capaz de deixar as pessoas sabem que o nosso software é usado e que você saiba quando nós organizamos eventos que possam ser relevantes para você. <br />\n<br />\nAo enchimento Desta forma, você aceita que a associação Chamilo ou seus membros possam enviar informações por e-mail sobre eventos importantes ou atualizações do software Chamilo ou comunidade. Isto irá ajudar a comunidade a crescer como uma entidade organizada, onde o fluxo de informações, com um respeito permanente de seu tempo e sua privacidade. <br />\n<br />\nPor favor nota que você é <b> não é necessário </b> para preencher este formulário. Se você quiser permanecer anônimo, vamos perder a oportunidade de oferecer-lhe todos os privilégios de ser um administrador do portal registrado, mas nós vamos respeitar sua decisão. Basta deixar esta forma vazia e clique em \"Avançar\" <br/><br/>.";
$CompanyActivity = "atividade da sua empresa";
$PleaseAllowUsALittleTimeToSubscribeYouToOneOfOurCourses = "Por favor, permita-nos um pouco de tempo para se inscrever você para um dos nossos cursos Se você acha que esqueci de você, entre em contato com os administradores do portal normalmente você pode encontrar os detalhes de contato no rodapé desta página...";
$ManageSessionFields = "Gerenciar campos de sessão";
@ -6124,7 +6124,7 @@ $OnlyAccessFromYourGroup = "Só acessível a partir de seu grupo";
$CreateAssignmentPage = "Isto irá criar uma página wiki especial em que o professor pode descrever a tarefa e que serão ligadas automaticamente para as páginas wiki onde os alunos realizam a tarefa. Tanto o professor e páginas dos alunos são criados automaticamente. Nestas tarefas , os alunos só podem editar e ver DELE páginas, mas isso pode ser mudado facilmente se você precisar.";
$UserFolders = "Pastas de usuários";
$UserFolder = "Pasta do usuário";
$HelpUsersFolder = "informação visível para o professor SOMENTE:.\NA pasta usuários contém uma pasta para cada usuário que acessou-o através da ferramenta de documentos, ou quando qualquer arquivo foi enviado no curso através do editor on-line Se nem circunstâncias ocorreu, em seguida, nenhuma pasta do usuário terá sido criado. No caso de grupos, os arquivos que são enviados através do editor será adicionado na pasta de cada grupo, que só é acessível por estudantes deste grupo.\n<br/> <br/>\nOs usuários pasta e cada uma das pastas incluídas ficarão ocultas por padrão no para todos os alunos, mas cada aluno pode ver o conteúdo do seu/sua diretório através do editor online. No entanto, se um estudante conhece o endereço de um arquivo ou pasta de um outro estudante, ele pode ser capaz de acessá-lo.\n<br/> <br/>\nSe a pasta de um estudante é visível, outros alunos podem ver o que ele contém. Neste caso, o aluno que possui a pasta pode também (a partir da ferramenta documentos e somente em sua pasta/ela): criar e editar documentos web, converter um documento em um modelo para uso pessoal, criar e editar desenhos em SVG e PNG formatos, arquivos de áudio em formato WAV gravação, faça arquivos de áudio em MP3 a partir de um texto, faça snapshops a partir de uma webcam, enviar documentos, criar pastas, mover pastas e arquivos, excluir pastas e arquivos, e faça o download de backup de sua pasta/ela.\n<br/> <br/>\nAlém disso, a ferramenta documentos está sincronizado com o gerente do editor on-line de arquivos, pelo que as alterações nos documentos acionado em qualquer um deles afetará ambos.\n<br/> <br/>\nComo tal, a pasta de usuário é não só um lugar para depositar os arquivos, torna-se um gerente completo dos documentos estudantes usam durante o curso. Além disso, lembre-se que qualquer usuário pode copiar um arquivo que é visível a partir de qualquer pasta na ferramenta de documentos (ou não, ele é o proprietário) para seu/sua carteira ou documentos pessoais área de rede social, que estará disponível para ele / ela para uso em outros cursos.";
$HelpUsersFolder = "informação visível para o professor SOMENTE:.\nA pasta usuários contém uma pasta para cada usuário que acessou-o através da ferramenta de documentos, ou quando qualquer arquivo foi enviado no curso através do editor on-line Se nem circunstâncias ocorreu, em seguida, nenhuma pasta do usuário terá sido criado. No caso de grupos, os arquivos que são enviados através do editor será adicionado na pasta de cada grupo, que só é acessível por estudantes deste grupo.\n<br/> <br/>\nOs usuários pasta e cada uma das pastas incluídas ficarão ocultas por padrão no para todos os alunos, mas cada aluno pode ver o conteúdo do seu/sua diretório através do editor online. No entanto, se um estudante conhece o endereço de um arquivo ou pasta de um outro estudante, ele pode ser capaz de acessá-lo.\n<br/> <br/>\nSe a pasta de um estudante é visível, outros alunos podem ver o que ele contém. Neste caso, o aluno que possui a pasta pode também (a partir da ferramenta documentos e somente em sua pasta/ela): criar e editar documentos web, converter um documento em um modelo para uso pessoal, criar e editar desenhos em SVG e PNG formatos, arquivos de áudio em formato WAV gravação, faça arquivos de áudio em MP3 a partir de um texto, faça snapshops a partir de uma webcam, enviar documentos, criar pastas, mover pastas e arquivos, excluir pastas e arquivos, e faça o download de backup de sua pasta/ela.\n<br/> <br/>\nAlém disso, a ferramenta documentos está sincronizado com o gerente do editor on-line de arquivos, pelo que as alterações nos documentos acionado em qualquer um deles afetará ambos.\n<br/> <br/>\nComo tal, a pasta de usuário é não só um lugar para depositar os arquivos, torna-se um gerente completo dos documentos estudantes usam durante o curso. Além disso, lembre-se que qualquer usuário pode copiar um arquivo que é visível a partir de qualquer pasta na ferramenta de documentos (ou não, ele é o proprietário) para seu/sua carteira ou documentos pessoais área de rede social, que estará disponível para ele/ela para uso em outros cursos.";
$HelpFolderChat = "INFORMAÇÕES VISÍVEL SOMENTE PARA O PROFESSOR: pasta\n Está contém todas as sessões que foram abertas no chat. Embora as sessões de chat pode muitas vezes ser trivial, outros pode ser realmente interessante e digno de ser incorporada como um documento de trabalho adicional. Para fazer isso sem alterar a visibilidade desta pasta, tornar o arquivo visível e vinculá-lo a partir de onde você considerem adequadas. Não é recomendado fazer esta pasta visível a todos.";
$HelpFolderCertificates = "Informação visível para o professor SOMENTE:.. Pasta\nEste contém os vários modelos de certificados que foram criados para a ferramenta de classificação não é recomendável fazer esta pasta visível a todos";
$DestinationDirectory = "Pasta de destino";

@ -7003,10 +7003,24 @@ $GradebookEnableLockingTitle = "Activar bloqueo de Avaliacións para os profesor
$GradebookEnableLockingComment = "Unha vez activada, esta opción permitirá aos profesores bloquear calquera avaliación dentro do seu curso. Isto prohibirá ao profesor calquera modificación posterior dos resultados dos seus alumnos nos recursos usados para esta avaliación: exames, leccións, tarefas, etc. O único rol autorizado a desbloquear unha avaliación é o administrador. O profesor estará informado desta posibilidade ao intentar desbloquear a avaliación. Tanto o bloqueo como o desbloqueo estarán gardados no rexistro de actividades importantes do sistema.";
$LdapDescriptionComment = "<div class='normal-message'> <br /><ul><li>Autentificación LDAP : <br />Ver I. embaixo para configurar LDAP <br />Ver II. embaixo para activar a autentificación LDAP </li><br /><br /><li> Actualizar atributos de usuario, con datos LDAP, despois de autentificación CAS (ver <a href='settings.php?category=CAS'>CAS configuration </a>) : <br />Ver I. embaixo para configurar LDAP <br />Para autentificación con manexo de usuarios CAS, a activación de LDAP non é requerida. </li><br /></ul></div><br /><h4>I. Configuración LDAP</h4><h5>Editar arquivo main/auth/external_login/ldap.conf.php </h5>-&gt; Editar valores do array <code>&#36;extldap_config</code> <br /><br />Os parámetros son <br /><ul><li>cadea do dominio base (ex : 'base_dn' =&gt; 'DC=cblue,DC=be') </li><li>nome distinguido do admin (ex : 'admin_dn' =&gt;'CN=admin,dc=cblue,dc=be') </li><li>contrasinal de aministrador (ex : 'admin_password' =&gt; '123456') </li><li>host ldap (ex : 'host' =&gt; array('1.2.3.4', '2.3.4.5', '3.4.5.6')) </li><li>filtro (ex : 'filter' =&gt; '') </li><li>porto (ex : 'port' =&gt; 389) </li><li>versión do protocolo (2 ou 3) (ex : 'protocol_version' =&gt; 3) </li><li>user_search (ex : 'user_search' =&gt; 'sAMAccountName=%username%') </li><li>codificación (ex : 'encoding' =&gt; 'UTF-8') </li><li>update_userinfo (ex : 'update_userinfo' =&gt; true) </li></ul>-&gt; Para actualizar as correspondencias entre usuario e atributos LDAP, editar o array <code>&#36;extldap_user_correspondance</code> <br />Os valores do array son &lt;chamilo_field&gt; =&gt; &gt;ldap_field&gt; <br />A estrutura do array está explciada no arquivo main/auth/external_login/ldap.conf.php<br /><br /><br /><h4>II. Activar autenticación LDAP </h4><h5>Editar arquivo main/inc/conf/configuration.php </h5>-&gt; Descomentar as liñas <br />&#36;extAuthSource[&quot;extldap&quot;][&quot;login&quot;] =&#36;_configuration['root_sys'].&#36;_configuration['code_append'].&quot;auth/external_login/login.ldap.php&quot;;<br />&#36;extAuthSource[&quot;extldap&quot;][&quot;newUser&quot;] =&#36;_configuration['root_sys'].&#36;_configuration['code_append'].&quot;auth/external_login/newUser.ldap.php&quot;;<br /><br />N.B. : Os usuarios LDAP empregan os mesmos campos ca os usuarios da plataforma para facer login. <br />N.B. : A activación LDAP engade un menú Autentificación externa [LDAP] nas páxinas de usuario &quot;engadir ou modificar&quot;.";
$ShibbolethMainActivateTitle = "Autenticación Shibboleth";
$ShibbolethMainActivateComment = "En primeiro lugar, ten que configurar Shibboleth para o seu servidor web. Para configuralo en Chamilo: editar o arquivo main/auth/shibboleth/config/aai.class.php Modificar valores de \$result co nome dos atributos de Shibboleth \$result->unique_id = 'mail'; \$result->firstname = 'cn'; \$result->lastname = 'uid'; \$result->email = 'mail'; \$result->language = '-'; \$result->gender = '-'; \$result->address = '-'; \$result->staff_category = '-'; \$result->home_organization_type = '-'; \$result->home_organization = '-'; \$result->affiliation = '-'; \$result->persistent_id = '-'; ... Ir a Plug-in para engadir o botón 'Shibboleth Login' no seu campus de Chamilo.";
$ShibbolethMainActivateComment = "En primeiro lugar, ten que configurar Shibboleth para o seu servidor web. Para configuralo en Chamilo: editar o arquivo main/auth/shibboleth/config/aai.class.php Modificar valores de &#36;result co nome dos atributos de Shibboleth
<ul>
<li>&#36;result-&gt;unique_id = 'mail';</li>
<li>&#36;result-&gt;firstname = 'cn';</li>
<li>&#36;result-&gt;lastname = 'uid';</li>
<li>&#36;result-&gt;email = 'mail';</li>
<li>&#36;result-&gt;language = '-';</li>
<li>&#36;result-&gt;gender = '-';</li>
<li>&#36;result-&gt;address = '-';</li>
<li>&#36;result-&gt;staff_category = '-';</li><li>&#36;result-&gt;home_organization_type = '-';</li><li>&#36;result-&gt;home_organization = '-';</li>
<li>&#36;result-&gt;affiliation = '-';</li>
<li>&#36;result-&gt;persistent_id = '-';</li>
</ul>
...
Ir a Plug-in para engadir o botón 'Shibboleth Login' no seu campus de Chamilo.";
$LdapDescriptionTitle = "Autenticación LDAP";
$FacebookMainActivateTitle = "Autenticación Facebook";
$FacebookMainActivateComment = "En primeiro lugar, tense que crear unha aplicación de Facebook (ver https://developers.facebook.com/apps) cunha conta de Facebook. Nos parámetros de aplicacións de Facebook, o valor de dirección URL do sitio debe tener \"unha acción = fbconnect\" un parámetro GET (http://mychamilo.com/?action=fbconnect, por ejemplo). Entón, editar o arquivo main/auth/external_login/facebook.conf.php e ingresar en \"appId\" e \"secret\" os valores de \$facebook_config. Ir a Plug-in para engadir un botón configurable \"Facebook Login\" para o campus de Chamilo.";
$FacebookMainActivateComment = "En primeiro lugar, tense que crear unha aplicación de Facebook (ver https://developers.facebook.com/apps) cunha conta de Facebook. Nos parámetros de aplicacións de Facebook, o valor de dirección URL do sitio debe tener \"unha acción = fbconnect\" un parámetro GET (http://mychamilo.com/?action=fbconnect, por ejemplo). Entón, editar o arquivo main/auth/external_login/facebook.conf.php e ingresar en \"appId\" e \"secret\" os valores de &#36;facebook_config. Ir a Plug-in para engadir un botón configurable \"Facebook Login\" para o campus de Chamilo.";
$AnnouncementForGroup = "Anuncio para un grupo";
$AllGroups = "Todos os grupos";
$LanguagePriority1Title = "Prioridade do idioma 1";

@ -3458,7 +3458,7 @@ $Preserved = "Chroniony";
$ConfirmUnsubscribe = "Potwierdź usunięcie użytkownika";
$See = "Idź do";
$LastVisits = "Moje ostatnie logowania";
$IfYouWantToAddManyUsers = "Jeśli chcesz dodać listę użytkowników do szkolenia \t\t\, skontaktuj się z administratorem.";
$IfYouWantToAddManyUsers = "Jeśli chcesz dodać listę użytkowników do szkolenia, skontaktuj się z administratorem.";
$PassTooEasy = "to hasło jest zbyt proste. Zobacz przykład poniżej";
$AddedToCourse = "jest już zarejestrowany w kursie";
$UserAlreadyRegistered = "Użytkownik o tej nazwie jest już zarejestrowany w tym kursie.";

@ -1340,7 +1340,7 @@ $ExamPassX = "Pasado sa minimum na %s";
$ExamFail = "Bagsak";
$ExamTracking = "Pagsusubaybay sa pagsusulit";
$EnableCourseValidation = "Balidasyon ng mga kurso";
$EnableCourseValidationComment = "Kapag ang tampok na \Balidasyon ng kurso\" ay pinagana, ang isang guro ay hindi maaaring makapaglikha ng isang kurso nang nag-iisa. Siya ay dapat magsulat ng isang kahilingan sa kurso. Ang tagapangasiwa ng platform ay niriripaso ang kahilingan at aaprubahan ito o tatanggihan.<br />Ang tampok na ito ay umaasa sa 'automated e-mail messaing'; i-set ang Chamilo upang mag-access sa isang server ng email at gumamit ng isang nakatalagang e-mail account.";
$EnableCourseValidationComment = "Kapag ang tampok na 'Balidasyon ng kurso' ay pinagana, ang isang guro ay hindi maaaring makapaglikha ng isang kurso nang nag-iisa. Siya ay dapat magsulat ng isang kahilingan sa kurso. Ang tagapangasiwa ng platform ay niriripaso ang kahilingan at aaprubahan ito o tatanggihan.<br />Ang tampok na ito ay umaasa sa 'automated e-mail messaing'; i-set ang Chamilo upang mag-access sa isang server ng email at gumamit ng isang nakatalagang e-mail account.";
$CourseValidationTermsAndConditionsLink = "Balidasyon ng kurso - isang link sa mga takda at mga kondisyon";
$CourseValidationTermsAndConditionsLinkComment = "Ito ang URL sa \"Mga Takda at Mga Kondisyon\" na dokumento na balido sa pagagawa ng kahilingan sa kurso. Kung ang address ay naitakda rito, ang gumagamit ay dapat basahin at sumang-ayon sa mga takda at mga kondisyon bago ipadala ang isang kahilingan sa kurso.<br />Kung iyong pagganahin ang module ng \"Mga Takda at Mga Kondisyon\" at kung nais mong gamitin ang URL nito, hayaang walang laman ang setting na ito.";
$EnabledSVGTitle = "Lumikha at mag-edit ng mga SVG file";

@ -10332,13 +10332,13 @@ class learnpath
$selectedMinScore = [];
$selectedMaxScore = [];
$masteryScore = [];
while ($row = Database::fetch_array($result)) {
if ($row['id'] == $item_id) {
if ($row['iid'] == $item_id) {
$selectedMinScore[$row['prerequisite']] = $row['prerequisite_min_score'];
$selectedMaxScore[$row['prerequisite']] = $row['prerequisite_max_score'];
$masteryScore[$row['prerequisite']] = $row['mastery_score'];
}
$masteryScore[$row['iid']] = $row['mastery_score'];
$arrLP[] = [
'id' => $row['iid'],
'item_type' => $row['item_type'],

@ -62,21 +62,13 @@ if (!empty($exportReport) && !empty($format)) {
switch ($format) {
case 'xls':
$filename = 'survey_results_'.$survey_id.'.xlsx';
$data = SurveyUtil::export_complete_report_xls(
$survey_data,
$filename,
$userId
);
$data = SurveyUtil::export_complete_report_xls($survey_data, $filename, $userId);
exit;
break;
case 'csv':
default:
$data = SurveyUtil::export_complete_report(
$survey_data,
$userId
);
$data = SurveyUtil::export_complete_report($survey_data, $userId);
$filename = 'survey_results_'.$survey_id.'.csv';
header('Content-type: application/octet-stream');
header('Content-Type: application/force-download');

@ -225,7 +225,7 @@ class SurveyUtil
*/
public static function handle_reporting_actions($survey_data, $people_filled)
{
$action = isset($_GET['action']) ? $_GET['action'] : null;
$action = isset($_GET['action']) ? $_GET['action'] : '';
// Getting the number of question
$temp_questions_data = SurveyManager::get_questions($_GET['survey_id']);
@ -243,20 +243,22 @@ class SurveyUtil
// Counting the number of questions that are relevant for the reporting
$survey_data['number_of_questions'] = count($questions_data);
if ($action == 'questionreport') {
self::display_question_report($survey_data);
}
if ($action == 'userreport') {
self::display_user_report($people_filled, $survey_data);
}
if ($action == 'comparativereport') {
self::display_comparative_report();
}
if ($action == 'completereport') {
self::display_complete_report($survey_data);
}
if ($action == 'deleteuserreport') {
self::delete_user_report($_GET['survey_id'], $_GET['user']);
switch ($action) {
case 'questionreport':
self::display_question_report($survey_data);
break;
case 'userreport':
self::display_user_report($people_filled, $survey_data);
break;
case 'comparativereport':
self::display_comparative_report();
break;
case 'completereport':
self::display_complete_report($survey_data);
break;
case 'deleteuserreport':
self::delete_user_report($_GET['survey_id'], $_GET['user']);
break;
}
}
@ -373,7 +375,7 @@ class SurveyUtil
echo '<select name="user" onchange="jumpMenu(\'parent\',this,0)">';
echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
.Security::remove_XSS($_GET['action']).'&survey_id='.intval($_GET['survey_id']).'">'
.Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
.get_lang('SelectUser').'</option>';
foreach ($people_filled as $key => &$person) {
@ -389,8 +391,8 @@ class SurveyUtil
$id = $person;
}
echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
.Security::remove_XSS($_GET['action']).'&survey_id='.intval($_GET['survey_id']).'&user='
.Security::remove_XSS($id).'" ';
.Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&user='
.Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
if (isset($_GET['user']) && $_GET['user'] == $id) {
echo 'selected="selected"';
}
@ -425,7 +427,8 @@ class SurveyUtil
survey_question.question_id = survey_question_option.question_id AND
survey_question_option.c_id = $course_id
WHERE
survey_question.survey_id = '".intval($_GET['survey_id'])."' AND
survey_question NOT LIKE '%{{%' AND
survey_question.survey_id = '".$surveyId."' AND
survey_question.c_id = $course_id
ORDER BY survey_question.sort, survey_question_option.sort ASC";
$result = Database::query($sql);
@ -445,7 +448,7 @@ class SurveyUtil
$sql = "SELECT * FROM $table_survey_answer
WHERE
c_id = $course_id AND
survey_id = '".intval($_GET['survey_id'])."' AND
survey_id = '".$surveyId."' AND
user = '".Database::escape_string($_GET['user'])."'";
$result = Database::query($sql);
while ($row = Database::fetch_array($result, 'ASSOC')) {
@ -577,6 +580,7 @@ class SurveyUtil
WHERE
c_id = $course_id AND
survey_id='".$surveyId."' AND
survey_question NOT LIKE '%{{%' AND
type <>'pagebreak'
ORDER BY sort ASC
$limitStatement";
@ -957,8 +961,9 @@ class SurveyUtil
LEFT JOIN $table_survey_question_option o
ON q.question_id = o.question_id AND q.c_id = o.c_id
WHERE
survey_question NOT LIKE '%{{%' AND
q.survey_id = '".$surveyId."' AND
q.c_id = $course_id
q.c_id = $course_id
GROUP BY q.question_id
ORDER BY q.sort ASC";
$result = Database::query($sql);
@ -1016,6 +1021,7 @@ class SurveyUtil
LEFT JOIN $table_survey_question_option sqo
ON sq.question_id = sqo.question_id AND sq.c_id = sqo.c_id
WHERE
survey_question NOT LIKE '%{{%' AND
sq.survey_id = '".$surveyId."' AND
sq.c_id = $course_id
ORDER BY sq.sort ASC, sqo.sort ASC";
@ -1169,7 +1175,9 @@ class SurveyUtil
foreach ($possible_options as $question_id => &$possible_option) {
if ($questions[$question_id]['type'] == 'open' || $questions[$question_id]['type'] == 'comment') {
echo '<td align="center">';
echo $answers_of_user[$question_id]['0']['option_id'];
if (isset($answers_of_user[$question_id]) && isset($answers_of_user[$question_id]['0'])) {
echo $answers_of_user[$question_id]['0']['option_id'];
}
echo '</td>';
} else {
foreach ($possible_option as $option_id => &$value) {
@ -1210,17 +1218,16 @@ class SurveyUtil
*/
public static function export_complete_report($survey_data, $user_id = 0)
{
// Database table definitions
$table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
$table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
$table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
$surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
if (empty($surveyId)) {
return false;
}
$table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
$table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
$table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
// The first column
$return = ';';
@ -1245,12 +1252,17 @@ class SurveyUtil
count(options.question_option_id) as number_of_options
FROM $table_survey_question questions
LEFT JOIN $table_survey_question_option options
ON questions.question_id = options.question_id AND options.c_id = questions.c_id
ON
questions.question_id = options.question_id AND
options.c_id = questions.c_id
WHERE
questions.survey_id = '".$surveyId."' AND
survey_question NOT LIKE '%{{%' AND
questions.type <> 'pagebreak' AND
questions.survey_id = $surveyId AND
questions.c_id = $course_id
GROUP BY questions.question_id
ORDER BY questions.sort ASC";
$result = Database::query($sql);
while ($row = Database::fetch_array($result)) {
// We show the questions if
@ -1261,24 +1273,21 @@ class SurveyUtil
is_array($_POST['questions_filter']) &&
in_array($row['question_id'], $_POST['questions_filter']))
) {
// We do not show comment and pagebreak question types
if ($row['type'] != 'pagebreak') {
if ($row['number_of_options'] == 0 && ($row['type'] == 'open' || $row['type'] == 'comment')) {
if ($row['number_of_options'] == 0) {
$return .= str_replace(
"\r\n",
' ',
api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
)
.';';
} else {
for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
$return .= str_replace(
"\r\n",
' ',
api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
)
.';';
} else {
for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
$return .= str_replace(
"\r\n",
' ',
api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
)
.';';
}
}
}
}
@ -1300,7 +1309,7 @@ class SurveyUtil
}
}
$sql = "SELECT
$sql = "SELECT DISTINCT
survey_question.question_id,
survey_question.survey_id,
survey_question.survey_question,
@ -1312,11 +1321,13 @@ class SurveyUtil
survey_question_option.sort as option_sort
FROM $table_survey_question survey_question
LEFT JOIN $table_survey_question_option survey_question_option
ON
ON
survey_question.question_id = survey_question_option.question_id AND
survey_question_option.c_id = survey_question.c_id
WHERE
survey_question.survey_id = '".$surveyId."' AND
WHERE
survey_question NOT LIKE '%{{%' AND
survey_question.type <> 'pagebreak' AND
survey_question.survey_id = $surveyId AND
survey_question.c_id = $course_id
ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
$result = Database::query($sql);
@ -1331,30 +1342,35 @@ class SurveyUtil
in_array($row['question_id'], $_POST['questions_filter'])
)
) {
// We do not show comment and pagebreak question types
if ($row['type'] != 'pagebreak') {
$row['option_text'] = str_replace(["\r", "\n"], ['', ''], $row['option_text']);
$return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';';
$possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
$possible_answers_type[$row['question_id']] = $row['type'];
}
$row['option_text'] = str_replace(["\r", "\n"], ['', ''], $row['option_text']);
$return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';';
$possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
$possible_answers_type[$row['question_id']] = $row['type'];
}
}
$return .= "\n";
// Getting all the answers of the users
$old_user = '';
$answers_of_user = [];
$sql = "SELECT * FROM $table_survey_answer
WHERE c_id = $course_id AND survey_id='".$surveyId."'";
WHERE
c_id = $course_id AND
survey_id='".$surveyId."'
";
if ($user_id != 0) {
$sql .= "AND user='".Database::escape_string($user_id)."' ";
}
$sql .= "ORDER BY user ASC";
$sql .= ' ORDER BY user ASC ';
$questionIdList = array_keys($possible_answers_type);
$open_question_iterator = 1;
$result = Database::query($sql);
while ($row = Database::fetch_array($result)) {
while ($row = Database::fetch_array($result, 'ASSOC')) {
if (!in_array($row['question_id'], $questionIdList)) {
continue;
}
if ($old_user != $row['user'] && $old_user != '') {
$return .= self::export_complete_report_row(
$survey_data,
@ -1365,6 +1381,7 @@ class SurveyUtil
);
$answers_of_user = [];
}
if ($possible_answers_type[$row['question_id']] == 'open' ||
$possible_answers_type[$row['question_id']] == 'comment'
) {
@ -1376,6 +1393,7 @@ class SurveyUtil
}
$old_user = $row['user'];
}
// This is to display the last user
$return .= self::export_complete_report_row(
$survey_data,
@ -1535,8 +1553,12 @@ class SurveyUtil
count(options.question_option_id) as number_of_options
FROM $table_survey_question questions
LEFT JOIN $table_survey_question_option options
ON questions.question_id = options.question_id AND options.c_id = questions.c_id
ON
questions.question_id = options.question_id AND
options.c_id = questions.c_id
WHERE
survey_question NOT LIKE '%{{%' AND
questions.type <> 'pagebreak' AND
questions.survey_id = $surveyId AND
questions.c_id = $course_id
GROUP BY questions.question_id
@ -1550,9 +1572,20 @@ class SurveyUtil
(isset($_POST['submit_question_filter']) && is_array($_POST['questions_filter']) &&
in_array($row['question_id'], $_POST['questions_filter']))
) {
// We do not show comment and pagebreak question types
if ($row['type'] != 'pagebreak') {
if ($row['number_of_options'] == 0 && ($row['type'] == 'open' || $row['type'] == 'comment')) {
if ($row['number_of_options'] == 0 &&
($row['type'] == 'open' || $row['type'] == 'comment')
) {
$worksheet->setCellValueByColumnAndRow(
$column,
$line,
api_html_entity_decode(
strip_tags($row['survey_question']),
ENT_QUOTES
)
);
$column++;
} else {
for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
$worksheet->setCellValueByColumnAndRow(
$column,
$line,
@ -1562,18 +1595,6 @@ class SurveyUtil
)
);
$column++;
} else {
for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
$worksheet->setCellValueByColumnAndRow(
$column,
$line,
api_html_entity_decode(
strip_tags($row['survey_question']),
ENT_QUOTES
)
);
$column++;
}
}
}
}
@ -1596,21 +1617,23 @@ class SurveyUtil
// Getting all the questions and options (second line)
$sql = "SELECT
survey_question.question_id,
survey_question.survey_id,
survey_question.survey_question,
survey_question.display,
survey_question.sort,
survey_question.question_id,
survey_question.survey_id,
survey_question.survey_question,
survey_question.display,
survey_question.sort,
survey_question.type,
survey_question_option.question_option_id,
survey_question_option.option_text,
survey_question_option.question_option_id,
survey_question_option.option_text,
survey_question_option.sort as option_sort
FROM $table_survey_question survey_question
LEFT JOIN $table_survey_question_option survey_question_option
ON
survey_question.question_id = survey_question_option.question_id AND
ON
survey_question.question_id = survey_question_option.question_id AND
survey_question_option.c_id = survey_question.c_id
WHERE
WHERE
survey_question NOT LIKE '%{{%' AND
survey_question.type <> 'pagebreak' AND
survey_question.survey_id = $surveyId AND
survey_question.c_id = $course_id
ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
@ -1625,20 +1648,17 @@ class SurveyUtil
(isset($_POST['questions_filter']) && is_array($_POST['questions_filter']) &&
in_array($row['question_id'], $_POST['questions_filter']))
) {
// We do not show comment and pagebreak question types
if ($row['type'] != 'pagebreak') {
$worksheet->setCellValueByColumnAndRow(
$column,
$line,
api_html_entity_decode(
strip_tags($row['option_text']),
ENT_QUOTES
)
);
$possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
$possible_answers_type[$row['question_id']] = $row['type'];
$column++;
}
$worksheet->setCellValueByColumnAndRow(
$column,
$line,
api_html_entity_decode(
strip_tags($row['option_text']),
ENT_QUOTES
)
);
$possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
$possible_answers_type[$row['question_id']] = $row['type'];
$column++;
}
}
@ -1652,7 +1672,7 @@ class SurveyUtil
if ($user_id != 0) {
$sql .= " AND user='".intval($user_id)."' ";
}
$sql .= " ORDER BY user ASC";
$sql .= ' ORDER BY user ASC';
$open_question_iterator = 1;
$result = Database::query($sql);
@ -1673,7 +1693,9 @@ class SurveyUtil
$line++;
$column = 0;
}
if ($possible_answers_type[$row['question_id']] == 'open' || $possible_answers_type[$row['question_id']] == 'comment') {
if ($possible_answers_type[$row['question_id']] == 'open' ||
$possible_answers_type[$row['question_id']] == 'comment'
) {
$temp_id = 'open'.$open_question_iterator;
$answers_of_user[$row['question_id']][$temp_id] = $row;
$open_question_iterator++;
@ -1843,6 +1865,13 @@ class SurveyUtil
$optionsY = ['----'];
$defaults = [];
foreach ($questions as $key => &$question) {
// Ignored tagged questions
if ($question) {
if (strpos($question['question'], '{{') !== false) {
$question = null;
continue;
}
}
if (is_array($allowed_question_types)) {
if (in_array($question['type'], $allowed_question_types)) {
if (isset($_GET['xaxis']) && $_GET['xaxis'] == $question['question_id']) {
@ -1853,8 +1882,8 @@ class SurveyUtil
$defaults['yaxis'] = $question['question_id'];
}
$optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 50);
$optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 50);
$optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
$optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
}
}
}
@ -2053,9 +2082,9 @@ class SurveyUtil
$table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
$sql = "SELECT * FROM $table_survey_answer
WHERE
c_id = $course_id AND
survey_id='".intval($survey_id)."' AND
WHERE
c_id = $course_id AND
survey_id='".intval($survey_id)."' AND
question_id='".intval($question_id)."'
ORDER BY USER ASC";
$result = Database::query($sql);
@ -2308,7 +2337,7 @@ class SurveyUtil
) {
$insertId = Database::insert($table, $params);
if ($insertId) {
$sql = "UPDATE $table
$sql = "UPDATE $table
SET survey_invitation_id = $insertId
WHERE iid = $insertId";
Database::query($sql);
@ -2848,7 +2877,7 @@ class SurveyUtil
);
$actions[] = Display::url(
Display::return_icon('multiplicate_survey.png', get_lang('MultiplicateSurvey')),
Display::return_icon('multiplicate_survey.png', get_lang('MultiplicateQuestions')),
$codePath.'survey/survey_list.php?'
.http_build_query($params + ['action' => 'multiplicate', 'survey_id' => $survey_id])
);
@ -3095,9 +3124,9 @@ class SurveyUtil
ON (survey.author = user.user_id)
WHERE survey.c_id = $course_id
$search_restriction
$condition_session
$condition_session
GROUP BY survey.survey_id
ORDER BY col$column $direction
ORDER BY col$column $direction
LIMIT $from,$number_of_items
";
$res = Database::query($sql);
@ -3213,11 +3242,11 @@ class SurveyUtil
$efv = new ExtraFieldValue('survey');
$sql = "
SELECT
survey.survey_id AS col0,
survey.title AS col1,
survey.code AS col2,
count(survey_question.question_id) AS col3,
SELECT
survey.survey_id AS col0,
survey.title AS col1,
survey.code AS col2,
count(survey_question.question_id) AS col3,
"
.(api_is_western_name_order()
? "CONCAT(user.firstname, ' ', user.lastname)"
@ -3304,16 +3333,16 @@ class SurveyUtil
$filterDate = $allowSurveyAvailabilityDatetime ? $now->format('Y-m-d H:i') : $now->format('Y-m-d');
$sql = "SELECT *
FROM $table_survey survey
FROM $table_survey survey
INNER JOIN
$table_survey_invitation survey_invitation
ON (
survey.code = survey_invitation.survey_code AND
survey.c_id = survey_invitation.c_id AND
survey.c_id = survey_invitation.c_id AND
survey.session_id = survey_invitation.session_id
)
WHERE
survey_invitation.user = $user_id AND
survey_invitation.user = $user_id AND
survey.avail_from <= '$filterDate' AND
survey.avail_till >= '$filterDate' AND
survey.c_id = $course_id AND

@ -35,7 +35,6 @@ $is_allowedToTrack = Tracking::isAllowToTrack($session_id);
if (!$is_allowedToTrack) {
api_not_allowed(true);
exit;
}
// If the user is a HR director (drh)
@ -73,7 +72,6 @@ if (api_is_drh()) {
$coursesFollowedList = array_keys($coursesFollowedList);
if (!in_array($courseId, $coursesFollowedList)) {
api_not_allowed(true);
exit;
}
}
}
@ -342,7 +340,7 @@ if ($showReporting) {
// Show the charts part only if there are students subscribed to this course/session
if ($nbStudents > 0) {
$usersTracking = TrackingCourseLog::get_user_data(null, $nbStudents, null, 'DESC');
$usersTracking = TrackingCourseLog::get_user_data(null, $nbStudents, null, 'DESC', false);
$numberStudentsCompletedLP = 0;
$averageStudentsTestScore = 0;
$scoresDistribution = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
@ -412,7 +410,7 @@ if ($nbStudents > 0) {
$tpl->assign('number_students', $nbStudents);
$tpl->assign('top_students', $userScoreList);
$trackingSummaryLayout = $tpl->get_template("tracking/tracking_course_log.tpl");
$trackingSummaryLayout = $tpl->get_template('tracking/tracking_course_log.tpl');
$content = $tpl->fetch($trackingSummaryLayout);
echo $content;
@ -508,21 +506,50 @@ if (count($a_students) > 0) {
$table->set_header(3, get_lang('Login'), false);
$headers['login'] = get_lang('Login');
$table->set_header(4, get_lang('TrainingTime').'&nbsp;'.
Display::return_icon('info3.gif', get_lang('CourseTimeInfo'), ['align' => 'absmiddle', 'hspace' => '3px']), false, ['style' => 'width:110px;']);
$table->set_header(
4,
get_lang('TrainingTime').'&nbsp;'.
Display::return_icon('info3.gif', get_lang('CourseTimeInfo'), ['align' => 'absmiddle', 'hspace' => '3px']),
false,
['style' => 'width:110px;']
);
$headers['training_time'] = get_lang('TrainingTime');
$table->set_header(5, get_lang('CourseProgress').'&nbsp;'.
Display::return_icon('info3.gif', get_lang('ScormAndLPProgressTotalAverage'), ['align' => 'absmiddle', 'hspace' => '3px']), false, ['style' => 'width:110px;']);
Display::return_icon(
'info3.gif',
get_lang('ScormAndLPProgressTotalAverage'),
['align' => 'absmiddle', 'hspace' => '3px']
),
false,
['style' => 'width:110px;']
);
$headers['course_progress'] = get_lang('CourseProgress');
$table->set_header(6, get_lang('ExerciseProgress').'&nbsp;'.
Display::return_icon('info3.gif', get_lang('ExerciseProgressInfo'), ['align' => 'absmiddle', 'hspace' => '3px']), false, ['style' => 'width:110px;']);
Display::return_icon(
'info3.gif',
get_lang('ExerciseProgressInfo'),
['align' => 'absmiddle', 'hspace' => '3px']
),
false,
['style' => 'width:110px;']
);
$headers['exercise_progress'] = get_lang('ExerciseProgress');
$table->set_header(7, get_lang('ExerciseAverage').'&nbsp;'.
Display::return_icon('info3.gif', get_lang('ExerciseAverageInfo'), ['align' => 'absmiddle', 'hspace' => '3px']), false, ['style' => 'width:110px;']);
Display::return_icon('info3.gif', get_lang('ExerciseAverageInfo'), ['align' => 'absmiddle', 'hspace' => '3px']),
false,
['style' => 'width:110px;']
);
$headers['exercise_average'] = get_lang('ExerciseAverage');
$table->set_header(8, get_lang('Score').'&nbsp;'.
Display::return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage'), ['align' => 'absmiddle', 'hspace' => '3px']), false, ['style' => 'width:110px;']);
Display::return_icon(
'info3.gif',
get_lang('ScormAndLPTestTotalAverage'),
['align' => 'absmiddle', 'hspace' => '3px']
),
false,
['style' => 'width:110px;']
);
$headers['score'] = get_lang('Score');
$table->set_header(9, get_lang('Student_publication'), false);
$headers['student_publication'] = get_lang('Student_publication');
@ -633,19 +660,21 @@ if ($export_csv) {
}
ob_end_clean();
$csvContentInSession = Session::read('csv_content');
// Adding headers before the content.
array_unshift($csv_content, $csv_headers);
array_unshift($csvContentInSession, $csv_headers);
if ($session_id) {
$sessionData = [];
$sessionInfo = api_get_session_info($session_id);
$sessionDates = SessionManager::parseSessionDates($sessionInfo);
array_unshift($csv_content, [get_lang('Date'), $sessionDates['access']]);
array_unshift($csv_content, [get_lang('SessionName'), $sessionInfo['name']]);
array_unshift($csvContentInSession, [get_lang('Date'), $sessionDates['access']]);
array_unshift($csvContentInSession, [get_lang('SessionName'), $sessionInfo['name']]);
}
Export::arrayToCsv($csv_content, 'reporting_student_list');
Export::arrayToCsv($csvContentInSession, 'reporting_student_list');
exit;
}
Display::display_footer();

@ -45,13 +45,13 @@ class ImsLtiTool
/**
* @var string
*
* @ORM\Column(name="consumer_key", type="string")
* @ORM\Column(name="consumer_key", type="string", nullable=true)
*/
private $consumerKey = '';
/**
* @var string
*
* @ORM\Column(name="shared_secret", type="string")
* @ORM\Column(name="shared_secret", type="string", nullable=true)
*/
private $sharedSecret = '';
/**
@ -117,6 +117,8 @@ class ImsLtiTool
$this->gradebookEval =null;
$this->privacy = null;
$this->children = new ArrayCollection();
$this->consumerKey = null;
$this->sharedSecret = null;
}
/**
@ -283,13 +285,43 @@ class ImsLtiTool
foreach ($strings as $string) {
$pairs = explode('=', $string);
$key = self::parseCustomKey($pairs[0]);
$value = $pairs[1];
$params['custom_'.$pairs[0]] = $pairs[1];
$params['custom_'.$key] = $value;
}
return $params;
}
/**
* Map the key from custom param.
*
* @param string $key
*
* @return string
*/
private static function parseCustomKey($key)
{
$newKey = '';
$key = strtolower($key);
$split = str_split($key);
foreach ($split as $char) {
if (
($char >= 'a' && $char <= 'z') || ($char >= '0' && $char <= '9')
) {
$newKey .= $char;
continue;
}
$newKey .= '_';
}
return $newKey;
}
/**
* Set activeDeepLinking.
*

@ -125,8 +125,8 @@ class ImsLtiPlugin extends Plugin
name VARCHAR(255) NOT NULL,
description LONGTEXT DEFAULT NULL,
launch_url VARCHAR(255) NOT NULL,
consumer_key VARCHAR(255) NOT NULL,
shared_secret VARCHAR(255) NOT NULL,
consumer_key VARCHAR(255) DEFAULT NULL,
shared_secret VARCHAR(255) DEFAULT NULL,
custom_params LONGTEXT DEFAULT NULL,
active_deep_linking TINYINT(1) DEFAULT \'0\' NOT NULL,
privacy LONGTEXT DEFAULT NULL,
@ -466,4 +466,81 @@ class ImsLtiPlugin extends Plugin
return !empty($tool);
}
/**
* @param string $configUrl
*
* @return string
* @throws Exception
*/
public function getLaunchUrlFromCartridge($configUrl)
{
$options = [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_POST => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => '',
CURLOPT_SSL_VERIFYPEER => false,
];
$ch = curl_init($configUrl);
curl_setopt_array($ch, $options);
$content = curl_exec($ch);
$errno = curl_errno($ch);
curl_close($ch);
if ($errno !== 0) {
throw new Exception($this->get_lang('NoAccessToUrl'));
}
$xml = new SimpleXMLElement($content);
$result = $xml->xpath('blti:launch_url');
if (empty($result)) {
throw new Exception($this->get_lang('LaunchUrlNotFound'));
}
$launchUrl = $result[0];
return (string) $launchUrl;
}
/**
* @param array $params
*/
public function trimParams(array &$params)
{
foreach ($params as $key => $value) {
$newValue = preg_replace('/\s+/', ' ', $value);
$params[$key] = trim($newValue);
}
}
/**
* @param ImsLtiTool $tool
* @param array $params
*
* @return array
*/
public function removeUrlParamsFromLaunchParams(ImsLtiTool $tool, array &$params)
{
$urlQuery = parse_url($tool->getLaunchUrl(), PHP_URL_QUERY);
if (empty($urlQuery)) {
return $params;
}
$queryParams = [];
parse_str($urlQuery, $queryParams);
$queryKeys = array_keys($queryParams);
foreach ($queryKeys as $key) {
if (isset($params[$key])) {
unset($params[$key]);
}
}
}
}

@ -1,7 +1,7 @@
IMS/LTI plugin
===
Version 1.3 (beta)
Version 1.4 (beta)
This plugin is meant to be later integrated into Chamilo (in a major version
release).
@ -33,6 +33,9 @@ external tool.
**v1.3**
* Privacy settings added. Allow to indicate id the launcher's data
should be sent in request.
**v1.4**
* Allow create external tools when there is no key/secret available for launch
# Installation
@ -75,3 +78,10 @@ CREATE INDEX IDX_C5E47F7C727ACA70 ON plugin_ims_lti_tool (parent_id);
```sql
ALTER TABLE plugin_ims_lti_tool ADD privacy LONGTEXT DEFAULT NULL;
```
**To v.4**
```sql
ALTER TABLE plugin_ims_lti_tool
CHANGE consumer_key consumer_key VARCHAR(255) DEFAULT NULL,
CHANGE shared_secret shared_secret VARCHAR(255) DEFAULT NULL;
```

@ -49,15 +49,6 @@ switch ($action) {
->setDescription(
empty($formValues['description']) ? null : $formValues['description']
)
->setLaunchUrl(
$baseTool ? $baseTool->getLaunchUrl() : $formValues['launch_url']
)
->setConsumerKey(
$baseTool ? $baseTool->getConsumerKey() : $formValues['consumer_key']
)
->setSharedSecret(
$baseTool ? $baseTool->getSharedSecret() : $formValues['shared_secret']
)
->setCustomParams(
empty($formValues['custom_params']) ? null : $formValues['custom_params']
)
@ -69,6 +60,33 @@ switch ($action) {
!empty($formValues['share_picture'])
);
if ($baseTool) {
$tool
->setLaunchUrl($baseTool->getLaunchUrl())
->setConsumerKey($baseTool->getConsumerKey())
->setSharedSecret($baseTool->getSharedSecret());
} else {
if (empty($formValues['consumer_key']) && empty($formValues['shared_secret'])) {
try {
$launchUrl = $plugin->getLaunchUrlFromCartridge($formValues['launch_url']);
} catch (Exception $e) {
Display::addFlash(
Display::return_message($e->getMessage(), 'error')
);
header('Location: '.api_get_self().'?'.api_get_cidreq());
exit;
}
$tool->setLaunchUrl($launchUrl);
} else {
$tool
->setLaunchUrl($formValues['launch_url'])
->setConsumerKey($formValues['consumer_key'])
->setSharedSecret($formValues['shared_secret']);
}
}
if (null === $baseTool ||
($baseTool && !$baseTool->isActiveDeepLinking())
) {

@ -21,11 +21,12 @@ if ($form->validate()) {
$externalTool = new ImsLtiTool();
$externalTool
->setName($formValues['name'])
->setDescription($formValues['description'])
->setLaunchUrl($formValues['launch_url'])
->setConsumerKey($formValues['consumer_key'])
->setSharedSecret($formValues['shared_secret'])
->setCustomParams($formValues['custom_params'])
->setDescription(
empty($formValues['description']) ? null : $formValues['description']
)
->setCustomParams(
empty($formValues['custom_params']) ? null : $formValues['custom_params']
)
->setCourse(null)
->setActiveDeepLinking(
isset($formValues['deep_linking'])
@ -36,6 +37,30 @@ if ($form->validate()) {
isset($formValues['share_picture'])
);
if (empty($formValues['consumer_key']) && empty($formValues['shared_secret'])) {
try {
$launchUrl = $plugin->getLaunchUrlFromCartridge($formValues['launch_url']);
} catch (Exception $e) {
Display::addFlash(
Display::return_message($e->getMessage(), 'error')
);
header('Location: '.api_get_path(WEB_PLUGIN_PATH).'ims_lti/admin.php');
exit;
}
$externalTool->setLaunchUrl($launchUrl);
} else {
$externalTool
->setLaunchUrl($formValues['launch_url'])
->setConsumerKey(
empty($formValues['consumer_key']) ? null : $formValues['consumer_key']
)
->setSharedSecret(
empty($formValues['shared_secret']) ? null : $formValues['shared_secret']
);
}
$em->persist($externalTool);
$em->flush();

@ -37,8 +37,12 @@ if ($form->validate()) {
$tool
->setName($formValues['name'])
->setDescription($formValues['description'])
->setCustomParams($formValues['custom_params'])
->setDescription(
empty($formValues['description']) ? null : $formValues['description']
)
->setCustomParams(
empty($formValues['custom_params']) ? null : $formValues['custom_params']
)
->setPrivacy(
!empty($formValues['share_name']),
!empty($formValues['share_email']),
@ -48,8 +52,12 @@ if ($form->validate()) {
if (null === $tool->getParent()) {
$tool
->setLaunchUrl($formValues['launch_url'])
->setConsumerKey($formValues['consumer_key'])
->setSharedSecret($formValues['shared_secret']);
->setConsumerKey(
empty($formValues['consumer_key']) ? null : $formValues['consumer_key']
)
->setSharedSecret(
empty($formValues['shared_secret']) ? null : $formValues['shared_secret']
);
}
if (null === $tool->getParent() ||

@ -109,22 +109,33 @@ $params['tool_consumer_instance_guid'] = $platformDomain;
$params['tool_consumer_instance_name'] = api_get_setting('siteName');
$params['tool_consumer_instance_url'] = api_get_path(WEB_PATH);
$params['tool_consumer_instance_contact_email'] = api_get_setting('emailAdministrator');
$params['oauth_callback'] = 'about:blank';
$params += $tool->parseCustomParams();
$oauth = new OAuthSimple(
$tool->getConsumerKey(),
$tool->getSharedSecret()
);
$oauth->setAction('post');
$oauth->setSignatureMethod('HMAC-SHA1');
$oauth->setParameters($params);
$result = $oauth->sign(array(
'path' => $tool->getLaunchUrl(),
'parameters' => array(
'oauth_callback' => 'about:blank'
)
));
$imsLtiPlugin->trimParams($params);
if (!empty($tool->getConsumerKey()) && !empty($tool->getSharedSecret())) {
$consumer = new OAuthConsumer(
$tool->getConsumerKey(),
$tool->getSharedSecret(),
null
);
$hmacMethod = new OAuthSignatureMethod_HMAC_SHA1();
$request = OAuthRequest::from_consumer_and_token(
$consumer,
'',
'POST',
$tool->getLaunchUrl(),
$params
);
$request->sign_request($hmacMethod, $consumer, '');
$params = $request->get_parameters();
}
$imsLtiPlugin->removeUrlParamsFromLaunchParams($tool, $params);
?>
<!DOCTYPE html>
<html>
@ -134,19 +145,10 @@ $result = $oauth->sign(array(
<body>
<form action="<?php echo $tool->getLaunchUrl() ?>" name="ltiLaunchForm" method="post"
encType="application/x-www-form-urlencoded">
<?php
foreach ($result["parameters"] as $key => $values) { //Dump parameters
echo '<input type="hidden" name="'.$key.'" value="'.htmlspecialchars($values).'" />'.PHP_EOL;
}
?>
<button type="submit">
<?php echo $imsLtiPlugin->get_lang('PressToContinue') ?>
</button>
<?php foreach ($params as $key => $value) { ?>
<input type="hidden" name="<?php echo $key ?>" value="<?php echo htmlspecialchars($value) ?>">
<?php } ?>
</form>
<script language="javascript">
document.querySelector('form [type="submit"]').style.display = "none";
document.ltiLaunchForm.submit();
</script>
<script>document.ltiLaunchForm.submit();</script>
</body>
</html>

@ -36,3 +36,5 @@ $strings['ShareLauncherPicture'] = 'Share launcher\'s picture';
$strings['NoTool'] = 'Tool not exists';
$strings['ToolAddedOnCourseX'] = 'Tool addeed on course <strong>%s</strong>.';
$strings['SupportDeppLinkingHelp'] = 'Contact your Tool Provider to verify if Deep Linking support is mandatory';
$strings['NoAccessToUrl'] = 'No access to URL';
$strings['LaunchUrlNotFound'] = 'Launch URL not found';

@ -36,3 +36,5 @@ $strings['ShareLauncherPicture'] = 'Enviar la foto del usuario';
$strings['NoTool'] = 'La herramienta no existe';
$strings['ToolAddedOnCourseX'] = 'Herramienta agregada en el curso <strong>%s</strong>.';
$strings['SupportDeppLinkingHelp'] = 'Contacte a su Proveedor de Herramienta para verificar si el soporte a Deep Linking es obligatorio';
$strings['NoAccessToUrl'] = 'Sin acceso a la URL';
$strings['LaunchUrlNotFound'] = 'URL de lanzamiento no encontrada';

@ -43,8 +43,8 @@ class FrmAdd extends FormValidator
if (null === $this->baseTool) {
$this->addUrl('launch_url', $plugin->get_lang('LaunchUrl'), true);
$this->addText('consumer_key', $plugin->get_lang('ConsumerKey'));
$this->addText('shared_secret', $plugin->get_lang('SharedSecret'));
$this->addText('consumer_key', $plugin->get_lang('ConsumerKey'), false);
$this->addText('shared_secret', $plugin->get_lang('SharedSecret'), false);
}
$this->addButtonAdvancedSettings('lti_adv');
@ -72,8 +72,6 @@ class FrmAdd extends FormValidator
$this->addCheckBox('share_picture', null, $plugin->get_lang('ShareLauncherPicture'));
$this->addHtml('</div>');
$this->addButtonCreate($plugin->get_lang('AddExternalTool'));
$this->applyFilter('__ALL__', 'Security::remove_XSS');
$this->applyFilter('__ALL__', 'htmlspecialchars_decode');
$this->applyFilter('__ALL__', 'trim');
}

@ -60,8 +60,8 @@ class FrmEdit extends FormValidator
if (null === $parent) {
$this->addUrl('launch_url', $plugin->get_lang('LaunchUrl'), true);
$this->addText('consumer_key', $plugin->get_lang('ConsumerKey'));
$this->addText('shared_secret', $plugin->get_lang('SharedSecret'));
$this->addText('consumer_key', $plugin->get_lang('ConsumerKey'), false);
$this->addText('shared_secret', $plugin->get_lang('SharedSecret'), false);
}
$this->addButtonAdvancedSettings('lti_adv');
@ -91,8 +91,6 @@ class FrmEdit extends FormValidator
$this->addButtonUpdate($plugin->get_lang('EditExternalTool'));
$this->addHidden('id', $this->tool->getId());
$this->addHidden('action', 'edit');
$this->applyFilter('__ALL__', 'Security::remove_XSS');
$this->applyFilter('__ALL__', 'htmlspecialchars_decode');
$this->applyFilter('__ALL__', 'trim');
}

@ -18,7 +18,9 @@ if (!$tool) {
$imsLtiPlugin = ImsLtiPlugin::create();
$template = new Template($tool->getName());
$pageTitle = Security::remove_XSS($tool->getName());
$template = new Template($pageTitle);
$template->assign('tool', $tool);
$template->assign(
'launch_url',
@ -27,6 +29,6 @@ $template->assign(
$content = $template->fetch('ims_lti/view/start.tpl');
$template->assign('header', $tool->getName());
$template->assign('header', $pageTitle);
$template->assign('content', $content);
$template->display_one_col_template();

@ -0,0 +1,42 @@
# Created by https://www.gitignore.io/api/osx,svn,composer
### OSX ###
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### SVN ###
.svn/
### Composer ###
composer.phar
/vendor/
# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# composer.lock

@ -0,0 +1,44 @@
### 2016.02.10
----
* Added composer.json
* Separated classes to separate files
### 2008.08.04
----
* Added LICENSE.txt file with MIT license, copyright owner is perhaps
dubious however.
### 2008.07.22
----
* Change to encoding to fix last change to encoding of spaces
### 2008.07.15
----
* Another change to encoding per:
[http://groups.google.com/group/oauth/browse_thread/thread/d39931d39b4af4bd](http://groups.google.com/group/oauth/browse_thread/thread/d39931d39b4af4bd)
* A change to port handling to better deal with https and the like per:
[http://groups.google.com/group/oauth/browse_thread/thread/1b203a51d9590226](http://groups.google.com/group/oauth/browse_thread/thread/1b203a51d9590226)
* Fixed a small bug per:
[https://github.com/jtsternberg/oauth/issues/26](https://github.com/jtsternberg/oauth/issues/26)
* Added missing base_string debug info when using RSA-SHA1
* Increased size of example endpoint input field and added note about
query strings
### 2009-2011.03.28
----
* Heaps of bug-fixes
* Introduction of PHPUnit testcases (which aided in above mentioned bug-fixes)
* Added support Revision A auth flows.
* Possibly more, I've lost track..
### 2001.03.29
----
* Fixed issue with hosts not being normalized correctly
[http://tools.ietf.org/html/rfc5849#section-3.4.1.2](http://tools.ietf.org/html/rfc5849#section-3.4.1.2)
[https://github.com/jtsternberg/oauth/issues/176](https://github.com/jtsternberg/oauth/issues/176)
[https://github.com/jtsternberg/oauth/issues/187](https://github.com/jtsternberg/oauth/issues/187)
* Changed signature comparing to be timing insensitive
[https://github.com/jtsternberg/oauth/issues/178](https://github.com/jtsternberg/oauth/issues/178)
* Fixed issue with Host header on some servers on non-standard port includes the port-number
[https://github.com/jtsternberg/oauth/issues/170](https://github.com/jtsternberg/oauth/issues/170)
[https://github.com/jtsternberg/oauth/issues/192](https://github.com/jtsternberg/oauth/issues/192)

@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2007 Andy Smith
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -0,0 +1,6 @@
# OAuth1 PHP
[Andy Smith](http://term.ie/)'s basic php library for OAuth. Original code taken from google code. For reference (and since google code is going away), I have ported the entire project to github. [You can find it here](https://github.com/jtsternberg/oauth).
To use this, be sure to run `composer install` in the root of the lib.
I have also split out the spec portion of the google code repo to [its own repo](https://github.com/jtsternberg/oauth-spec).

@ -0,0 +1,16 @@
<?php
class OAuthConsumer {
public $key;
public $secret;
function __construct($key, $secret, $callback_url=NULL) {
$this->key = $key;
$this->secret = $secret;
$this->callback_url = $callback_url;
}
function __toString() {
return "OAuthConsumer[key=$this->key,secret=$this->secret]";
}
}

@ -0,0 +1,27 @@
<?php
class OAuthDataStore {
function lookup_consumer($consumer_key) {
// implement me
}
function lookup_token($consumer, $token_type, $token) {
// implement me
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
// implement me
}
function new_request_token($consumer, $callback = null) {
// return a new token attached to this consumer
}
function new_access_token($token, $consumer, $verifier = null) {
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
}
}

@ -0,0 +1,7 @@
<?php
/* Generic exception class
*/
class OAuthException extends Exception {
// pass
}

@ -0,0 +1,260 @@
<?php
class OAuthRequest {
protected $parameters;
protected $http_method;
protected $http_url;
// for debug purposes
public $base_string;
public static $version = '1.0';
public static $POST_INPUT = 'php://input';
function __construct($http_method, $http_url, $parameters=NULL) {
$parameters = ($parameters) ? $parameters : array();
$parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
$this->parameters = $parameters;
$this->http_method = $http_method;
$this->http_url = $http_url;
}
/**
* attempt to build up a request from what was passed to the server
*/
public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
$scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
? 'http'
: 'https';
$http_url = ($http_url) ? $http_url : $scheme .
'://' . $_SERVER['SERVER_NAME'] .
':' .
$_SERVER['SERVER_PORT'] .
$_SERVER['REQUEST_URI'];
$http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD'];
// We weren't handed any parameters, so let's find the ones relevant to
// this request.
// If you run XML-RPC or similar you should use this to provide your own
// parsed parameter-list
if (!$parameters) {
// Find request headers
$request_headers = OAuthUtil::get_headers();
// Parse the query-string to find GET parameters
$parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
// It's a POST request of the proper content-type, so parse POST
// parameters and add those overriding any duplicates from GET
if ($http_method == "POST"
&& isset($request_headers['Content-Type'])
&& strstr($request_headers['Content-Type'],
'application/x-www-form-urlencoded')
) {
$post_data = OAuthUtil::parse_parameters(
file_get_contents(self::$POST_INPUT)
);
$parameters = array_merge($parameters, $post_data);
}
// We have a Authorization-header with OAuth data. Parse the header
// and add those overriding any duplicates from GET or POST
if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') {
$header_parameters = OAuthUtil::split_header(
$request_headers['Authorization']
);
$parameters = array_merge($parameters, $header_parameters);
}
}
return new OAuthRequest($http_method, $http_url, $parameters);
}
/**
* pretty much a helper function to set up the request
*/
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
$parameters = ($parameters) ? $parameters : array();
$defaults = array("oauth_version" => OAuthRequest::$version,
"oauth_nonce" => OAuthRequest::generate_nonce(),
"oauth_timestamp" => OAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key);
if ($token)
$defaults['oauth_token'] = $token->key;
$parameters = array_merge($defaults, $parameters);
return new OAuthRequest($http_method, $http_url, $parameters);
}
public function set_parameter($name, $value, $allow_duplicates = true) {
if ($allow_duplicates && isset($this->parameters[$name])) {
// We have already added parameter(s) with this name, so add to the list
if (is_scalar($this->parameters[$name])) {
// This is the first duplicate, so transform scalar (string)
// into an array so we can add the duplicates
$this->parameters[$name] = array($this->parameters[$name]);
}
$this->parameters[$name][] = $value;
} else {
$this->parameters[$name] = $value;
}
}
public function get_parameter($name) {
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
}
public function get_parameters() {
return $this->parameters;
}
public function unset_parameter($name) {
unset($this->parameters[$name]);
}
/**
* The request parameters, sorted and concatenated into a normalized string.
* @return string
*/
public function get_signable_parameters() {
// Grab all parameters
$params = $this->parameters;
// Remove oauth_signature if present
// Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
if (isset($params['oauth_signature'])) {
unset($params['oauth_signature']);
}
return OAuthUtil::build_http_query($params);
}
/**
* Returns the base string of this request
*
* The base string defined as the method, the url
* and the parameters (normalized), each urlencoded
* and the concated with &.
*/
public function get_signature_base_string() {
$parts = array(
$this->get_normalized_http_method(),
$this->get_normalized_http_url(),
$this->get_signable_parameters()
);
$parts = OAuthUtil::urlencode_rfc3986($parts);
return implode('&', $parts);
}
/**
* just uppercases the http method
*/
public function get_normalized_http_method() {
return strtoupper($this->http_method);
}
/**
* parses the url and rebuilds it to be
* scheme://host/path
*/
public function get_normalized_http_url() {
$parts = parse_url($this->http_url);
$scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http';
$port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80');
$host = (isset($parts['host'])) ? strtolower($parts['host']) : '';
$path = (isset($parts['path'])) ? $parts['path'] : '';
if (($scheme == 'https' && $port != '443')
|| ($scheme == 'http' && $port != '80')) {
$host = "$host:$port";
}
return "$scheme://$host$path";
}
/**
* builds a url usable for a GET request
*/
public function to_url() {
$post_data = $this->to_postdata();
$out = $this->get_normalized_http_url();
if ($post_data) {
$out .= '?'.$post_data;
}
return $out;
}
/**
* builds the data one would send in a POST request
*/
public function to_postdata() {
return OAuthUtil::build_http_query($this->parameters);
}
/**
* builds the Authorization: header
*/
public function to_header($realm=null) {
$first = true;
if($realm) {
$out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
$first = false;
} else
$out = 'Authorization: OAuth';
$total = array();
foreach ($this->parameters as $k => $v) {
if (substr($k, 0, 5) != "oauth") continue;
if (is_array($v)) {
throw new OAuthException('Arrays not supported in headers');
}
$out .= ($first) ? ' ' : ',';
$out .= OAuthUtil::urlencode_rfc3986($k) .
'="' .
OAuthUtil::urlencode_rfc3986($v) .
'"';
$first = false;
}
return $out;
}
public function __toString() {
return $this->to_url();
}
public function sign_request($signature_method, $consumer, $token) {
$this->set_parameter(
"oauth_signature_method",
$signature_method->get_name(),
false
);
$signature = $this->build_signature($signature_method, $consumer, $token);
$this->set_parameter("oauth_signature", $signature, false);
}
public function build_signature($signature_method, $consumer, $token) {
$signature = $signature_method->build_signature($this, $consumer, $token);
return $signature;
}
/**
* util function: current timestamp
*/
private static function generate_timestamp() {
return time();
}
/**
* util function: current nonce
*/
private static function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
}
}

@ -0,0 +1,223 @@
<?php
class OAuthServer {
protected $timestamp_threshold = 300; // in seconds, five minutes
protected $version = '1.0'; // hi blaine
protected $signature_methods = array();
protected $data_store;
function __construct($data_store) {
$this->data_store = $data_store;
}
public function add_signature_method($signature_method) {
$this->signature_methods[$signature_method->get_name()] =
$signature_method;
}
// high level functions
/**
* process a request_token request
* returns the request token on success
*/
public function fetch_request_token(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
// no token required for the initial token request
$token = NULL;
$this->check_signature($request, $consumer, $token);
// Rev A change
$callback = $request->get_parameter('oauth_callback');
$new_token = $this->data_store->new_request_token($consumer, $callback);
return $new_token;
}
/**
* process an access_token request
* returns the access token on success
*/
public function fetch_access_token(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
// requires authorized request token
$token = $this->get_token($request, $consumer, "request");
$this->check_signature($request, $consumer, $token);
// Rev A change
$verifier = $request->get_parameter('oauth_verifier');
$new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
return $new_token;
}
/**
* verify an api call, checks all the parameters
*/
public function verify_request(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
$token = $this->get_token($request, $consumer, "access");
$this->check_signature($request, $consumer, $token);
return array($consumer, $token);
}
// Internals from here
/**
* version 1
*/
private function get_version(&$request) {
$version = $request->get_parameter("oauth_version");
if (!$version) {
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
// Chapter 7.0 ("Accessing Protected Ressources")
$version = '1.0';
}
if ($version !== $this->version) {
throw new OAuthException("OAuth version '$version' not supported");
}
return $version;
}
/**
* figure out the signature with some defaults
*/
private function get_signature_method($request) {
$signature_method = $request instanceof OAuthRequest
? $request->get_parameter("oauth_signature_method")
: NULL;
if (!$signature_method) {
// According to chapter 7 ("Accessing Protected Ressources") the signature-method
// parameter is required, and we can't just fallback to PLAINTEXT
throw new OAuthException('No signature method parameter. This parameter is required');
}
if (!in_array($signature_method,
array_keys($this->signature_methods))) {
throw new OAuthException(
"Signature method '$signature_method' not supported " .
"try one of the following: " .
implode(", ", array_keys($this->signature_methods))
);
}
return $this->signature_methods[$signature_method];
}
/**
* try to find the consumer for the provided request's consumer key
*/
private function get_consumer($request) {
$consumer_key = $request instanceof OAuthRequest
? $request->get_parameter("oauth_consumer_key")
: NULL;
if (!$consumer_key) {
throw new OAuthException("Invalid consumer key");
}
$consumer = $this->data_store->lookup_consumer($consumer_key);
if (!$consumer) {
throw new OAuthException("Invalid consumer");
}
return $consumer;
}
/**
* try to find the token for the provided request's token key
*/
private function get_token($request, $consumer, $token_type="access") {
$token_field = $request instanceof OAuthRequest
? $request->get_parameter('oauth_token')
: NULL;
$token = $this->data_store->lookup_token(
$consumer, $token_type, $token_field
);
if (!$token) {
throw new OAuthException("Invalid $token_type token: $token_field");
}
return $token;
}
/**
* all-in-one function to check the signature on a request
* should guess the signature method appropriately
*/
private function check_signature($request, $consumer, $token) {
// this should probably be in a different method
$timestamp = $request instanceof OAuthRequest
? $request->get_parameter('oauth_timestamp')
: NULL;
$nonce = $request instanceof OAuthRequest
? $request->get_parameter('oauth_nonce')
: NULL;
$this->check_timestamp($timestamp);
$this->check_nonce($consumer, $token, $nonce, $timestamp);
$signature_method = $this->get_signature_method($request);
$signature = $request->get_parameter('oauth_signature');
$valid_sig = $signature_method->check_signature(
$request,
$consumer,
$token,
$signature
);
if (!$valid_sig) {
throw new OAuthException("Invalid signature");
}
}
/**
* check that the timestamp is new enough
*/
private function check_timestamp($timestamp) {
if( ! $timestamp )
throw new OAuthException(
'Missing timestamp parameter. The parameter is required'
);
// verify that timestamp is recentish
$now = time();
if (abs($now - $timestamp) > $this->timestamp_threshold) {
throw new OAuthException(
"Expired timestamp, yours $timestamp, ours $now"
);
}
}
/**
* check that the nonce is not repeated
*/
private function check_nonce($consumer, $token, $nonce, $timestamp) {
if( ! $nonce )
throw new OAuthException(
'Missing nonce parameter. The parameter is required'
);
// verify that the nonce is uniqueish
$found = $this->data_store->lookup_nonce(
$consumer,
$token,
$nonce,
$timestamp
);
if ($found) {
throw new OAuthException("Nonce already used: $nonce");
}
}
}

@ -0,0 +1,55 @@
<?php
/**
* A class for implementing a Signature Method
* See section 9 ("Signing Requests") in the spec
*/
abstract class OAuthSignatureMethod {
/**
* Needs to return the name of the Signature Method (ie HMAC-SHA1)
* @return string
*/
abstract public function get_name();
/**
* Build up the signature
* NOTE: The output of this function MUST NOT be urlencoded.
* the encoding is handled in OAuthRequest when the final
* request is serialized
* @param OAuthRequest $request
* @param OAuthConsumer $consumer
* @param OAuthToken $token
* @return string
*/
abstract public function build_signature($request, $consumer, $token);
/**
* Verifies that a given signature is correct
* @param OAuthRequest $request
* @param OAuthConsumer $consumer
* @param OAuthToken $token
* @param string $signature
* @return bool
*/
public function check_signature($request, $consumer, $token, $signature) {
$built = $this->build_signature($request, $consumer, $token);
// Check for zero length, although unlikely here
if (strlen($built) == 0 || strlen($signature) == 0) {
return false;
}
if (strlen($built) != strlen($signature)) {
return false;
}
// Avoid a timing leak with a (hopefully) time insensitive compare
$result = 0;
for ($i = 0; $i < strlen($signature); $i++) {
$result |= ord($built{$i}) ^ ord($signature{$i});
}
return $result == 0;
}
}

@ -0,0 +1,30 @@
<?php
/**
* The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as
* defined in [RFC2104] where the Signature Base String is the text and the
* key is the concatenated values (each first encoded per Parameter Encoding)
* of the Consumer Secret and Token Secret, separated by an '&' character
* (ASCII code 38) even if empty.
* - Chapter 9.2 ("HMAC-SHA1")
*/
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
function get_name() {
return "HMAC-SHA1";
}
public function build_signature($request, $consumer, $token) {
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
$key_parts = array(
$consumer->secret,
($token) ? $token->secret : ""
);
$key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
$key = implode('&', $key_parts);
return base64_encode(hash_hmac('sha1', $base_string, $key, true));
}
}

@ -0,0 +1,34 @@
<?php
/**
* The PLAINTEXT method does not provide any security protection and SHOULD only be used
* over a secure channel such as HTTPS. It does not use the Signature Base String.
* - Chapter 9.4 ("PLAINTEXT")
*/
class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
public function get_name() {
return "PLAINTEXT";
}
/**
* oauth_signature is set to the concatenated encoded values of the Consumer Secret and
* Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
* empty. The result MUST be encoded again.
* - Chapter 9.4.1 ("Generating Signatures")
*
* Please note that the second encoding MUST NOT happen in the SignatureMethod, as
* OAuthRequest handles this!
*/
public function build_signature($request, $consumer, $token) {
$key_parts = array(
$consumer->secret,
($token) ? $token->secret : ""
);
$key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
$key = implode('&', $key_parts);
$request->base_string = $key;
return $key;
}
}

@ -0,0 +1,69 @@
<?php
/**
* The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
* [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
* EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
* verified way to the Service Provider, in a manner which is beyond the scope of this
* specification.
* - Chapter 9.3 ("RSA-SHA1")
*/
abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
public function get_name() {
return "RSA-SHA1";
}
// Up to the SP to implement this lookup of keys. Possible ideas are:
// (1) do a lookup in a table of trusted certs keyed off of consumer
// (2) fetch via http using a url provided by the requester
// (3) some sort of specific discovery code based on request
//
// Either way should return a string representation of the certificate
protected abstract function fetch_public_cert(&$request);
// Up to the SP to implement this lookup of keys. Possible ideas are:
// (1) do a lookup in a table of trusted certs keyed off of consumer
//
// Either way should return a string representation of the certificate
protected abstract function fetch_private_cert(&$request);
public function build_signature($request, $consumer, $token) {
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
// Fetch the private key cert based on the request
$cert = $this->fetch_private_cert($request);
// Pull the private key ID from the certificate
$privatekeyid = openssl_get_privatekey($cert);
// Sign using the key
$ok = openssl_sign($base_string, $signature, $privatekeyid);
// Release the key resource
openssl_free_key($privatekeyid);
return base64_encode($signature);
}
public function check_signature($request, $consumer, $token, $signature) {
$decoded_sig = base64_decode($signature);
$base_string = $request->get_signature_base_string();
// Fetch the public key cert based on the request
$cert = $this->fetch_public_cert($request);
// Pull the public key ID from the certificate
$publickeyid = openssl_get_publickey($cert);
// Check the computed signature against the one passed in the query
$ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
// Release the key resource
openssl_free_key($publickeyid);
return $ok == 1;
}
}

@ -0,0 +1,13 @@
<phpunit colors="true">
<testsuite name="OAuth">
<directory>tests</directory>
</testsuite>
<filter>
<blacklist>
<directory>tests</directory>
</blacklist>
</filter>
<logging>
<log type="coverage-html" target="./report" charset="UTF-8" yui="true" highlight="false" lowUpperBound="35" highLowerBound="70"/>
</logging>
</phpunit>

@ -0,0 +1,31 @@
<?php
class OAuthToken {
// access tokens and request tokens
public $key;
public $secret;
/**
* key = the token
* secret = the token secret
*/
function __construct($key, $secret) {
$this->key = $key;
$this->secret = $secret;
}
/**
* generates the basic string serialization of a token that a server
* would respond to request_token and access_token calls with
*/
function to_string() {
return "oauth_token=" .
oauthutil::urlencode_rfc3986($this->key) .
"&oauth_token_secret=" .
oauthutil::urlencode_rfc3986($this->secret);
}
function __tostring() {
return $this->to_string();
}
}

@ -0,0 +1,153 @@
<?php
class OAuthUtil {
public static function urlencode_rfc3986($input) {
if (is_array($input)) {
return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
} else if (is_scalar($input)) {
return str_replace(
'+',
' ',
str_replace('%7E', '~', rawurlencode($input))
);
} else {
return '';
}
}
// This decode function isn't taking into consideration the above
// modifications to the encoding process. However, this method doesn't
// seem to be used anywhere so leaving it as is.
public static function urldecode_rfc3986($string) {
return urldecode($string);
}
// Utility function for turning the Authorization: header into
// parameters, has to do some unescaping
// Can filter out any non-oauth parameters if needed (default behaviour)
// May 28th, 2010 - method updated to tjerk.meesters for a speed improvement.
// see http://code.google.com/p/oauth/issues/detail?id=163
public static function split_header($header, $only_allow_oauth_parameters = true) {
$params = array();
if (preg_match_all('/('.($only_allow_oauth_parameters ? 'oauth_' : '').'[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches)) {
foreach ($matches[1] as $i => $h) {
$params[$h] = OAuthUtil::urldecode_rfc3986(empty($matches[3][$i]) ? $matches[4][$i] : $matches[3][$i]);
}
if (isset($params['realm'])) {
unset($params['realm']);
}
}
return $params;
}
// helper to try to sort out headers for people who aren't running apache
public static function get_headers() {
if (function_exists('apache_request_headers')) {
// we need this to get the actual Authorization: header
// because apache tends to tell us it doesn't exist
$headers = apache_request_headers();
// sanitize the output of apache_request_headers because
// we always want the keys to be Cased-Like-This and arh()
// returns the headers in the same case as they are in the
// request
$out = array();
foreach ($headers AS $key => $value) {
$key = str_replace(
" ",
"-",
ucwords(strtolower(str_replace("-", " ", $key)))
);
$out[$key] = $value;
}
} else {
// otherwise we don't have apache and are just going to have to hope
// that $_SERVER actually contains what we need
$out = array();
if( isset($_SERVER['CONTENT_TYPE']) )
$out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
if( isset($_ENV['CONTENT_TYPE']) )
$out['Content-Type'] = $_ENV['CONTENT_TYPE'];
foreach ($_SERVER as $key => $value) {
if (substr($key, 0, 5) == "HTTP_") {
// this is chaos, basically it is just there to capitalize the first
// letter of every word that is not an initial HTTP and strip HTTP
// code from przemek
$key = str_replace(
" ",
"-",
ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
);
$out[$key] = $value;
}
}
}
return $out;
}
// This function takes a input like a=b&a=c&d=e and returns the parsed
// parameters like this
// array('a' => array('b','c'), 'd' => 'e')
public static function parse_parameters( $input ) {
if (!isset($input) || !$input) return array();
$pairs = explode('&', $input);
$parsed_parameters = array();
foreach ($pairs as $pair) {
$split = explode('=', $pair, 2);
$parameter = OAuthUtil::urldecode_rfc3986($split[0]);
$value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
if (isset($parsed_parameters[$parameter])) {
// We have already recieved parameter(s) with this name, so add to the list
// of parameters with this name
if (is_scalar($parsed_parameters[$parameter])) {
// This is the first duplicate, so transform scalar (string) into an array
// so we can add the duplicates
$parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
}
$parsed_parameters[$parameter][] = $value;
} else {
$parsed_parameters[$parameter] = $value;
}
}
return $parsed_parameters;
}
public static function build_http_query($params) {
if (!$params) return '';
// Urlencode both keys and values
$keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
$values = OAuthUtil::urlencode_rfc3986(array_values($params));
$params = array_combine($keys, $values);
// Parameters are sorted by name, using lexicographical byte value ordering.
// Ref: Spec: 9.1.1 (1)
uksort($params, 'strcmp');
$pairs = array();
foreach ($params as $parameter => $value) {
if (is_array($value)) {
// If two or more parameters share the same name, they are sorted by their value
// Ref: Spec: 9.1.1 (1)
// June 12th, 2010 - changed to sort because of issue 164 by hidetaka
sort($value, SORT_STRING);
foreach ($value as $duplicate_value) {
$pairs[] = $parameter . '=' . $duplicate_value;
}
} else {
$pairs[] = $parameter . '=' . $value;
}
}
// For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
// Each name-value pair is separated by an '&' character (ASCII code 38)
return implode('&', $pairs);
}
}

@ -0,0 +1,106 @@
<?php //vim: foldmethod=marker
//require_once("../init.php");
class TestOAuthServer extends OAuthServer {
public function get_signature_methods() {
return $this->signature_methods;
}
}
class TestOAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod_RSA_SHA1 {
public function fetch_private_cert(&$request) {
$cert = <<<EOD
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V
A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d
7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ
hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H
X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm
uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw
rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z
zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn
qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG
WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno
cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+
3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8
AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54
Lw03eHTNQghS0A==
-----END PRIVATE KEY-----
EOD;
return $cert;
}
public function fetch_public_cert(&$request) {
$cert = <<<EOD
-----BEGIN CERTIFICATE-----
MIIBpjCCAQ+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAZMRcwFQYDVQQDDA5UZXN0
IFByaW5jaXBhbDAeFw03MDAxMDEwODAwMDBaFw0zODEyMzEwODAwMDBaMBkxFzAV
BgNVBAMMDlRlc3QgUHJpbmNpcGFsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlY
zypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp/IpH7kH41Etb
mUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQABMA0GCSqGSIb3
DQEBBQUAA4GBAGZLPEuJ5SiJ2ryq+CmEGOXfvlTtEL2nuGtr9PewxkgnOjZpUy+d
4TvuXJbNQc8f4AMWL/tO9w0Fk80rWKp9ea8/df4qMq5qlFWlx6yOLQxumNOmECKb
WpkUQDIDJEoFUzKMVuJf4KO/FJ345+BNLGgbJ6WujreoM1X/gYfdnJ/J
-----END CERTIFICATE-----
EOD;
return $cert;
}
}
/**
* A mock store for testing
*/
class MockOAuthDataStore extends OAuthDataStore {/*{{{*/
private $consumer;
private $request_token;
private $access_token;
private $nonce;
function __construct() {/*{{{*/
$this->consumer = new OAuthConsumer("key", "secret", NULL);
$this->request_token = new OAuthToken("requestkey", "requestsecret", 1);
$this->access_token = new OAuthToken("accesskey", "accesssecret", 1);
$this->nonce = "nonce";
}/*}}}*/
function lookup_consumer($consumer_key) {/*{{{*/
if ($consumer_key == $this->consumer->key) return $this->consumer;
return NULL;
}/*}}}*/
function lookup_token($consumer, $token_type, $token) {/*{{{*/
$token_attrib = $token_type . "_token";
if ($consumer->key == $this->consumer->key
&& $token == $this->$token_attrib->key) {
return $this->$token_attrib;
}
return NULL;
}/*}}}*/
function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
if ($consumer->key == $this->consumer->key
&& (($token && $token->key == $this->request_token->key)
|| ($token && $token->key == $this->access_token->key))
&& $nonce == $this->nonce) {
return $this->nonce;
}
return NULL;
}/*}}}*/
function new_request_token($consumer) {/*{{{*/
if ($consumer->key == $this->consumer->key) {
return $this->request_token;
}
return NULL;
}/*}}}*/
function new_access_token($token, $consumer) {/*{{{*/
if ($consumer->key == $this->consumer->key
&& $token->key == $this->request_token->key) {
return $this->access_token;
}
return NULL;
}/*}}}*/
}/*}}}*/
?>

@ -0,0 +1,30 @@
{
"name": "jtsternberg/oauth1-php",
"description": "Andy Smith's basic php library for OAuth.",
"license": "MIT",
"authors": [
{
"name": "Andy Smith",
"homepage": "http://term.ie/",
"role": "Developer"
},
{
"name": "Justin Sternberg",
"email": "justin@dsgnwrks.pro",
"homepage": "https://dsgnwrks.pro",
"role": "Developer"
}
],
"keywords": ["oauth", "oauth1", "php"],
"homepage": "https://github.com/jtsternberg/oauth1-php",
"support": {
"issues": "https://github.com/jtsternberg/oauth1-php/issues",
"source": "https://github.com/jtsternberg/oauth1-php"
},
"require": {
"php": ">5.3"
},
"autoload": {
"classmap": ["code"]
}
}

@ -0,0 +1,20 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "9ec16f80a40b9ed7b9501632e2ab33c3",
"content-hash": "17d848aa0b54718b6bf5334fd7e94bcc",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">5.3"
},
"platform-dev": []
}

@ -0,0 +1,73 @@
## Interfaces:
**OAuthConsumer** is a data type that represents the identity of the Consumer via its shared secret with the Service Provider.
OAuthConsumer
- `key : str`
- `secret : str`
**OAuthToken** is a data type that represents an End User via either an access or request token
OAuthToken
- `token : str`
- `secret : str`
- `to_string() -> str`
- `(static) from_string() -> OAuthToken`
**OAuthSignatureMethod** is a strategy class that implements a signature method
OAuthSignatureMethod
- `get_name() -> str`
- `build_signature (OAuthRequest, OAuthConsumer, OAuthToken) -> str`
**OAuthRequest** represents the request and can be seriali
OAuthRequest:
- `OAuthRequest(str http_method, str http_url, [dict parameters]) -> constructor`
- `set_parameter(str parameter, str value) -> void`
- `example parameters: oauth_consumer_key, foo`
- `get_parameter(str parameter) -> str`
- `get_parameters() -> dict`
- `get_normalized_http_method() -> str`
- `get_normalized_http_url() -> str`
- `get_signable_params() -> dict`
- `to_header () -> str // serialize as a header for an HTTPAuth request`
- `to_postdata () -> str // serialize as post data for a POST request`
- `to_url () -> str // serialize as a url for a GET request`
- `sign_request(OAuthSignatureMethod, OAuthConsumer, OAuthToken) -> void`
- `build_signature(OAuthSignatureMethod, OAuthConsumer, OAuthToken) -> str`
- `(static) from_request([str http_method, str http_url, dict parameters])`
- `(static) from_consumer_and_token(OAuthConsumer, OAuthToken, str http_method, str http_url, [dict parameters]) -> OAuthRequest`
**OAuthServer** is a worker to check a requests validity against a data store
OAuthServer:
- `OAuthServer(OAuthDataStore) -> constructor`
- `set_data_store(OAuthDataStore) -> void`
- `get_data_store() -> OAuthDataStore`
- `fetch_request_token (OAuthRequest) -> OAuthToken`
- `fetch_access_token (OAuthRequest) -> OAuthToken`
- `verify_request (OAuthRequest) -> OAuthToken`
**OAuthClient** is a worker to attempt to execute a request
OAuthClient:
- `OAuthClient(OAuthConsumer, OAuthToken) -> constructor`
- `get_consumer() -> OAuthConsumer`
- `get_token() -> OAuthToken`
- `fetch_request_token (OAuthRequest) -> OAuthToken`
- `fetch_access_token (OAuthRequest) -> OAuthToken`
**OAuthDataStore** is a database abstraction used to lookup consumers and tokens
OAuthDataStore:
- `lookup_consumer(str key) -> OAuthConsumer`
- `lookup_token(OAuthConsumer, str token_type, str token_token) -> OAuthToken`
- `lookup_nonce(OAuthConsumer, OAuthToken, str nonce, int timestamp) -> OAuthToken`
- `fetch_request_token(OAuthConsumer) -> OAuthToken`
- `fetch_access_token(OAuthConsumer, OAuthToken) -> OAuthToken`

@ -0,0 +1,74 @@
<?php
/* A very naive dbm-based oauth storage
*
* NOTE: This is for reference ONLY,
* and contains, amongst others, a hole
* where you can get the token secret
* easily..
*/
class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/
private $dbh;
function __construct($path = "oauth.gdbm") {/*{{{*/
$this->dbh = dba_popen($path, 'c', 'gdbm');
}/*}}}*/
function __destruct() {/*{{{*/
dba_close($this->dbh);
}/*}}}*/
function lookup_consumer($consumer_key) {/*{{{*/
$rv = dba_fetch("consumer_$consumer_key", $this->dbh);
if ($rv === FALSE) {
return NULL;
}
$obj = unserialize($rv);
if (!($obj instanceof OAuthConsumer)) {
return NULL;
}
return $obj;
}/*}}}*/
function lookup_token($consumer, $token_type, $token) {/*{{{*/
$rv = dba_fetch("${token_type}_${token}", $this->dbh);
if ($rv === FALSE) {
return NULL;
}
$obj = unserialize($rv);
if (!($obj instanceof OAuthToken)) {
return NULL;
}
return $obj;
}/*}}}*/
function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
if (dba_exists("nonce_$nonce", $this->dbh)) {
return TRUE;
} else {
dba_insert("nonce_$nonce", "1", $this->dbh);
return FALSE;
}
}/*}}}*/
function new_token($consumer, $type="request") {/*{{{*/
$key = md5(time());
$secret = time() + time();
$token = new OAuthToken($key, md5(md5($secret)));
if (!dba_insert("${type}_$key", serialize($token), $this->dbh)) {
throw new OAuthException("doooom!");
}
return $token;
}/*}}}*/
function new_request_token($consumer) {/*{{{*/
return $this->new_token($consumer, "request");
}/*}}}*/
function new_access_token($token, $consumer) {/*{{{*/
$token = $this->new_token($consumer, 'access');
dba_delete("request_" . $token->key, $this->dbh);
return $token;
}/*}}}*/
}/*}}}*/

@ -0,0 +1,14 @@
<?php
require_once("common.inc.php");
try {
$req = OAuthRequest::from_request();
$token = $test_server->fetch_access_token($req);
print $token;
} catch (OAuthException $e) {
print($e->getMessage() . "\n<hr />\n");
print_r($req);
die();
}
?>

@ -0,0 +1,133 @@
<?php
require_once("common.inc.php");
$key = @$_REQUEST['key'];
$secret = @$_REQUEST['secret'];
$token = @$_REQUEST['token'];
$token_secret = @$_REQUEST['token_secret'];
$endpoint = @$_REQUEST['endpoint'];
$action = @$_REQUEST['action'];
$dump_request = @$_REQUEST['dump_request'];
$user_sig_method = @$_REQUEST['sig_method'];
$sig_method = $hmac_method;
if ($user_sig_method) {
$sig_method = $sig_methods[$user_sig_method];
}
$test_consumer = new OAuthConsumer($key, $secret, NULL);
$test_token = NULL;
if ($token) {
$test_token = new OAuthConsumer($token, $token_secret);
}
if ($action == "request_token") {
$parsed = parse_url($endpoint);
$params = array();
parse_str($parsed['query'], $params);
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, NULL, "GET", $endpoint, $params);
$req_req->sign_request($sig_method, $test_consumer, NULL);
if ($dump_request) {
Header('Content-type: text/plain');
print "request url: " . $req_req->to_url(). "\n";
print_r($req_req);
exit;
}
Header("Location: $req_req");
}
else if ($action == "authorize") {
$callback_url = "$base_url/client.php?key=$key&secret=$secret&token=$token&token_secret=$token_secret&endpoint=" . urlencode($endpoint);
$auth_url = $endpoint . "?oauth_token=$token&oauth_callback=".urlencode($callback_url);
if ($dump_request) {
Header('Content-type: text/plain');
print("auth_url: " . $auth_url);
exit;
}
Header("Location: $auth_url");
}
else if ($action == "access_token") {
$parsed = parse_url($endpoint);
$params = array();
parse_str($parsed['query'], $params);
$acc_req = OAuthRequest::from_consumer_and_token($test_consumer, $test_token, "GET", $endpoint, $params);
$acc_req->sign_request($sig_method, $test_consumer, $test_token);
if ($dump_request) {
Header('Content-type: text/plain');
print "request url: " . $acc_req->to_url() . "\n";
print_r($acc_req);
exit;
}
Header("Location: $acc_req");
}
?>
<html>
<head>
<title>OAuth Test Client</title>
</head>
<body>
<div><a href="index.php">server</a> | <a href="client.php">client</a></div>
<h1>OAuth Test Client</h1>
<h2>Instructions for Use</h2>
<p>This is a test client that will let you test your OAuth server code. Enter the appropriate information below to test.</p>
<p>Note: we don't store any of the information you type in.</p>
<form method="POST" name="oauth_client">
<h3>Choose a Signature Method</h3>
<select name="sig_method">
<?php
foreach ($sig_methods as $name=> $method) {
$selected = "";
if ($name == $sig_method->get_name()) {
$selected = " selected='selected'";
}
print "<option value='$name'$selected>$name</option>\n";
}
?>
</select>
<h3>Enter The Endpoint to Test</h3>
endpoint: <input type="text" name="endpoint" value="<?php echo $endpoint; ?>" size="100"/><br />
<small style="color: green">Note: You can include query parameters in there to have them parsed in and signed too</small>
<h3>Enter Your Consumer Key / Secret</h3>
consumer key: <input type="text" name="key" value="<?php echo $key; ?>" /><br />
consumer secret: <input type="text" name="secret" value="<?php echo $secret;?>" /><br />
dump request, don't redirect: <input type="checkbox" name="dump_request" value="1" <?php if ($dump_request) echo 'checked="checked"'; ?>/><br />
make a token request (don't forget to copy down the values you get)
<input type="submit" name="action" value="request_token" />
<h3>Enter Your Request Token / Secret</h3>
token: <input type="text" name="token" value="<?php echo $token; ?>" /><br />
token secret: <input type="text" name="token_secret" value="<?php echo $token_secret; ?>" /><br />
<p><strong>Don't forget to update your endpoint to point at the auth or access token url</strong></p>
try to authorize this token: <input type="submit" name="action" value="authorize" /><br />
try to get an access token: <input type="submit" name="action" value="access_token" /><br />
<h3>Currently Supported Signature Methods</h3>
<p>Current signing method is: <?php echo $sig_method->get_name() ?></p>
<ul>
<?php
foreach ($sig_methods as $key => $method) {
print "<li>$key";
if ($key != $sig_method->get_name()) {
print "(<a href='?sig_method=$key'>switch</a>)";
}
print "</li>\n";
}
?>
</ul>
<?php
if ("RSA-SHA1" == $sig_method->get_name()) {
// passing test_server as a dummy referecne
print "<pre>" . $sig_method->fetch_private_cert($test_server). "</pre>\n";
print "<pre>" . $sig_method->fetch_public_cert($test_server) . "</pre>\n";
}
?>
<h3>Further Resources</h3>
<p>There is also a <a href="index.php">test server</a> implementation in here.</p>
<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>
</body>

@ -0,0 +1,26 @@
<?php
require_once("../init.php");
require_once("../code/OAuth_TestServer.php");
/*
* Config Section
*/
$domain = $_SERVER['HTTP_HOST'];
$base = "/oauth/example";
$base_url = "http://$domain$base";
/**
* Some default objects
*/
$test_server = new TestOAuthServer(new MockOAuthDataStore());
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
$plaintext_method = new OAuthSignatureMethod_PLAINTEXT();
$rsa_method = new TestOAuthSignatureMethod_RSA_SHA1();
$test_server->add_signature_method($hmac_method);
$test_server->add_signature_method($plaintext_method);
$test_server->add_signature_method($rsa_method);
$sig_methods = $test_server->get_signature_methods();
?>

@ -0,0 +1,21 @@
<?php
require_once("common.inc.php");
try {
$req = OAuthRequest::from_request();
list($consumer, $token) = $test_server->verify_request($req);
// lsit back the non-OAuth params
$total = array();
foreach($req->get_parameters() as $k => $v) {
if (substr($k, 0, 5) == "oauth") continue;
$total[] = urlencode($k) . "=" . urlencode($v);
}
print implode("&", $total);
} catch (OAuthException $e) {
print($e->getMessage() . "\n<hr />\n");
print_r($req);
die();
}
?>

@ -0,0 +1,108 @@
<?php
require_once("common.inc.php");
$test_consumer = new OAuthConsumer("key", "secret", NULL);
$req_token = new OAuthConsumer("requestkey", "requestsecret", 1);
$acc_token = new OAuthConsumer("accesskey", "accesssecret", 1);
$sig_method = $hmac_method;
$user_sig_method = @$_GET['sig_method'];
if ($user_sig_method) {
$sig_method = $sig_methods[$user_sig_method];
}
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, NULL, "GET", $base_url . "/request_token.php");
$req_req->sign_request($sig_method, $test_consumer, NULL);
$acc_req = OAuthRequest::from_consumer_and_token($test_consumer, $req_token, "GET", $base_url . "/access_token.php");
$acc_req->sign_request($sig_method, $test_consumer, $req_token);
$echo_req = OAuthRequest::from_consumer_and_token($test_consumer, $acc_token, "GET", $base_url . "/echo_api.php", array("method"=> "foo%20bar", "bar" => "baz"));
$echo_req->sign_request($sig_method, $test_consumer, $acc_token);
?>
<html>
<head>
<title>OAuth Test Server</title>
</head>
<body>
<div><a href="index.php">server</a> | <a href="client.php">client</a></div>
<h1>OAuth Test Server</h1>
<h2>Instructions for Use</h2>
<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>
<h3>Your Consumer Key / Secret</h3>
<ul>
<li>consumer key: <code><strong>key</strong></code></li>
<li>consumer secret: <code><strong>secret</strong></code></li>
</ul>
<p>Use this key and secret for all your requests.</p>
<h3>Getting a Request Token</h3>
<ul>
<li>request token endpoint: <code><strong><?php echo $base_url . "/request_token.php"; ?></strong></code></li>
</ul>
<p>A successful request will return the following:</p>
<p><code>oauth_token=requestkey&amp;oauth_token_secret=requestsecret</code></p>
<p>An unsuccessful request will attempt to describe what went wrong.</p>
<h4>Example</h4>
<a href="<?php echo $req_req; ?>"><?php echo $req_req; ?></a>
<h3>Getting an Access Token</h3>
<p>The Request Token provided above is already authorized, you may use it to request an Access Token right away.</p>
<ul>
<li>access token endpoint: <code><strong><?php echo $base_url . "/access_token.php"; ?></strong></code></li>
</ul>
<p>A successful request will return the following:</p>
<p><code>oauth_token=accesskey&amp;oauth_token_secret=accesssecret</code></p>
<p>An unsuccessful request will attempt to describe what went wrong.</p>
<h4>Example</h4>
<a href="<?php echo $acc_req; ?>"><?php echo $acc_req; ?></a>
<h3>Making Authenticated Calls</h3>
<p>Using your Access Token you can make authenticated calls.</p>
<ul>
<li>api endpoint: <code><strong><?php echo $base_url . "/echo_api.php"; ?></strong></code></li>
</ul>
<p>
A successful request will echo the non-OAuth parameters sent to it, for example:</p>
<p><code>method=foo&amp;bar=baz</code></p>
<p>An unsuccessful request will attempt to describe what went wrong.</p>
<h4>Example</h4>
<a href="<?php echo $echo_req; ?>"><?php echo $echo_req; ?></a>
<h3>Currently Supported Signature Methods</h3>
<p>Current signing method is: <?php echo $user_sig_method ?></p>
<ul>
<?php
$sig_methods = $test_server->get_signature_methods();
foreach ($sig_methods as $key => $method) {
print "<li>$key";
if ($key != $sig_method->get_name()) {
print "(<a href='?sig_method=$key'>switch</a>)";
}
print "</li>\n";
}
?>
</ul>
<?php
if ("RSA-SHA1" == $sig_method->get_name()) {
print "<pre>" . $sig_method->fetch_private_cert($req_req) . "</pre>\n";
print "<pre>" . $sig_method->fetch_public_cert($req_req) . "</pre>\n";
}
?>
<h3>Further Resources</h3>
<p>There is also a <a href="client.php">test client</a> implementation in here.</p>
<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>
</body>

@ -0,0 +1,14 @@
<?php
require_once("common.inc.php");
try {
$req = OAuthRequest::from_request();
$token = $test_server->fetch_request_token($req);
print $token;
} catch (OAuthException $e) {
print($e->getMessage() . "\n<hr />\n");
print_r($req);
die();
}
?>

@ -0,0 +1,5 @@
<?php
// Include the autoloader to get started.
// (make sure to run `composer install`!)
require_once dirname( __FILE__ ) . '/vendor/autoload.php';

@ -0,0 +1,12 @@
<?php
/**
* A very simple class that you can pass a base-string, and then have it returned again.
* Used for testing the signature-methods
*/
class Mock_OAuthBaseStringRequest {
private $provided_base_string;
public $base_string; // legacy
public function __construct($bs) { $this->provided_base_string = $bs; }
public function get_signature_base_string() { return $this->provided_base_string; }
}

@ -0,0 +1,57 @@
<?php
/**
* A mock store for testing
*/
class Mock_OAuthDataStore extends OAuthDataStore {
private $consumer;
private $request_token;
private $access_token;
private $nonce;
function __construct() {
$this->consumer = new OAuthConsumer("key", "secret", NULL);
$this->request_token = new OAuthToken("requestkey", "requestsecret", 1);
$this->access_token = new OAuthToken("accesskey", "accesssecret", 1);
$this->nonce = "nonce";
}
function lookup_consumer($consumer_key) {
if ($consumer_key == $this->consumer->key) return $this->consumer;
return NULL;
}
function lookup_token($consumer, $token_type, $token) {
$token_attrib = $token_type . "_token";
if ($consumer->key == $this->consumer->key
&& $token == $this->$token_attrib->key) {
return $this->$token_attrib;
}
return NULL;
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
if ($consumer->key == $this->consumer->key
&& (($token && $token->key == $this->request_token->key)
|| ($token && $token->key == $this->access_token->key))
&& $nonce == $this->nonce) {
return $this->nonce;
}
return NULL;
}
function new_request_token($consumer, $callback = null) {
if ($consumer->key == $this->consumer->key) {
return $this->request_token;
}
return NULL;
}
function new_access_token($token, $consumer, $verifier = null) {
if ($consumer->key == $this->consumer->key
&& $token->key == $this->request_token->key) {
return $this->access_token;
}
return NULL;
}
}

@ -0,0 +1,47 @@
<?php
/**
* A mock implementation of OAuthSignatureMethod_RSA_SHA1
* Always returns the signatures described in
* http://wiki.oauth.net/TestCases section 9.3 ("RSA-SHA1")
*/
class Mock_OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod_RSA_SHA1 {
public function fetch_private_cert(&$request) {
$cert = <<<EOD
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V
A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d
7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ
hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H
X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm
uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw
rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z
zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn
qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG
WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno
cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+
3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8
AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54
Lw03eHTNQghS0A==
-----END PRIVATE KEY-----
EOD;
return $cert;
}
public function fetch_public_cert(&$request) {
$cert = <<<EOD
-----BEGIN CERTIFICATE-----
MIIBpjCCAQ+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAZMRcwFQYDVQQDDA5UZXN0
IFByaW5jaXBhbDAeFw03MDAxMDEwODAwMDBaFw0zODEyMzEwODAwMDBaMBkxFzAV
BgNVBAMMDlRlc3QgUHJpbmNpcGFsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlY
zypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp/IpH7kH41Etb
mUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQABMA0GCSqGSIb3
DQEBBQUAA4GBAGZLPEuJ5SiJ2ryq+CmEGOXfvlTtEL2nuGtr9PewxkgnOjZpUy+d
4TvuXJbNQc8f4AMWL/tO9w0Fk80rWKp9ea8/df4qMq5qlFWlx6yOLQxumNOmECKb
WpkUQDIDJEoFUzKMVuJf4KO/FJ345+BNLGgbJ6WujreoM1X/gYfdnJ/J
-----END CERTIFICATE-----
EOD;
return $cert;
}
}

@ -0,0 +1,10 @@
<?php
require 'common.php';
class OAuthConsumerTest extends PHPUnit_Framework_TestCase {
public function testConvertToString() {
$consumer = new OAuthConsumer('key', 'secret');
$this->assertEquals('OAuthConsumer[key=key,secret=secret]', (string) $consumer);
}
}

@ -0,0 +1,329 @@
<?php
/*
* Tests of OAuthRequest
*
* The tests works by using OAuthTestUtils::build_request
* to populare $_SERVER, $_GET & $_POST.
*
* Most of the base string and signature tests
* are either very simple or based upon
* http://wiki.oauth.net/TestCases
*/
require_once dirname(__FILE__) . '/common.php';
class OAuthRequestTest extends PHPUnit_Framework_TestCase {
public function testCanGetSingleParameter() {
// Yes, a awesomely boring test.. But if this doesn't work, the other tests is unreliable
$request = new OAuthRequest('', '', array('test'=>'foo'));
$this->assertEquals( 'foo', $request->get_parameter('test'), 'Failed to read back parameter');
$request = new OAuthRequest('', '', array('test'=>array('foo', 'bar')));
$this->assertEquals( array('foo', 'bar'), $request->get_parameter('test'), 'Failed to read back parameter');
$request = new OAuthRequest('', '', array('test'=>'foo', 'bar'=>'baz'));
$this->assertEquals( 'foo', $request->get_parameter('test'), 'Failed to read back parameter');
$this->assertEquals( 'baz', $request->get_parameter('bar'), 'Failed to read back parameter');
}
public function testGetAllParameters() {
// Yes, a awesomely boring test.. But if this doesn't work, the other tests is unreliable
$request = new OAuthRequest('', '', array('test'=>'foo'));
$this->assertEquals( array('test'=>'foo'), $request->get_parameters(), 'Failed to read back parameters');
$request = new OAuthRequest('', '', array('test'=>'foo', 'bar'=>'baz'));
$this->assertEquals( array('test'=>'foo', 'bar'=>'baz'), $request->get_parameters(), 'Failed to read back parameters');
$request = new OAuthRequest('', '', array('test'=>array('foo', 'bar')));
$this->assertEquals( array('test'=>array('foo', 'bar')), $request->get_parameters(), 'Failed to read back parameters');
}
public function testSetParameters() {
$request = new OAuthRequest('', '');
$this->assertEquals( NULL, $request->get_parameter('test'), 'Failed to assert that non-existing parameter is NULL');
$request->set_parameter('test', 'foo');
$this->assertEquals( 'foo', $request->get_parameter('test'), 'Failed to set single-entry parameter');
$request->set_parameter('test', 'bar');
$this->assertEquals( array('foo', 'bar'), $request->get_parameter('test'), 'Failed to set single-entry parameter');
$request->set_parameter('test', 'bar', false);
$this->assertEquals( 'bar', $request->get_parameter('test'), 'Failed to set single-entry parameter');
}
public function testUnsetParameter() {
$request = new OAuthRequest('', '');
$this->assertEquals( NULL, $request->get_parameter('test'));
$request->set_parameter('test', 'foo');
$this->assertEquals( 'foo', $request->get_parameter('test'));
$request->unset_parameter('test');
$this->assertEquals( NULL, $request->get_parameter('test'), 'Failed to unset parameter');
}
public function testCreateRequestFromConsumerAndToken() {
$cons = new OAuthConsumer('key', 'kd94hf93k423kf44');
$token = new OAuthToken('token', 'pfkkdhi9sl3r4s00');
$request = OAuthRequest::from_consumer_and_token($cons, $token, 'POST', 'http://example.com');
$this->assertEquals('POST', $request->get_normalized_http_method());
$this->assertEquals('http://example.com', $request->get_normalized_http_url());
$this->assertEquals('1.0', $request->get_parameter('oauth_version'));
$this->assertEquals($cons->key, $request->get_parameter('oauth_consumer_key'));
$this->assertEquals($token->key, $request->get_parameter('oauth_token'));
$this->assertEquals(time(), $request->get_parameter('oauth_timestamp'));
$this->assertRegExp('/[0-9a-f]{32}/', $request->get_parameter('oauth_nonce'));
// We don't know what the nonce will be, except it'll be md5 and hence 32 hexa digits
$request = OAuthRequest::from_consumer_and_token($cons, $token, 'POST', 'http://example.com', array('oauth_nonce'=>'foo'));
$this->assertEquals('foo', $request->get_parameter('oauth_nonce'));
$request = OAuthRequest::from_consumer_and_token($cons, NULL, 'POST', 'http://example.com', array('oauth_nonce'=>'foo'));
$this->assertNull($request->get_parameter('oauth_token'));
// Test that parameters given in the $http_url instead of in the $parameters-parameter
// will still be picked up
$request = OAuthRequest::from_consumer_and_token($cons, $token, 'POST', 'http://example.com/?foo=bar');
$this->assertEquals('http://example.com/', $request->get_normalized_http_url());
$this->assertEquals('bar', $request->get_parameter('foo'));
}
public function testBuildRequestFromPost() {
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'foo=bar&baz=blargh');
$this->assertEquals(array('foo'=>'bar','baz'=>'blargh'), OAuthRequest::from_request()->get_parameters(), 'Failed to parse POST parameters');
}
public function testBuildRequestFromGet() {
OAuthTestUtils::build_request('GET', 'http://testbed/test?foo=bar&baz=blargh');
$this->assertEquals(array('foo'=>'bar','baz'=>'blargh'), OAuthRequest::from_request()->get_parameters(), 'Failed to parse GET parameters');
}
public function testBuildRequestFromHeader() {
$test_header = 'OAuth realm="",oauth_foo=bar,oauth_baz="bla,rgh"';
OAuthTestUtils::build_request('POST', 'http://testbed/test', '', $test_header);
$this->assertEquals(array('oauth_foo'=>'bar','oauth_baz'=>'bla,rgh'), OAuthRequest::from_request()->get_parameters(), 'Failed to split auth-header correctly');
}
public function testHasProperParameterPriority() {
$test_header = 'OAuth realm="",oauth_foo=header';
OAuthTestUtils::build_request('POST', 'http://testbed/test?oauth_foo=get', 'oauth_foo=post', $test_header);
$this->assertEquals('header', OAuthRequest::from_request()->get_parameter('oauth_foo'), 'Loaded parameters in with the wrong priorities');
OAuthTestUtils::build_request('POST', 'http://testbed/test?oauth_foo=get', 'oauth_foo=post');
$this->assertEquals('post', OAuthRequest::from_request()->get_parameter('oauth_foo'), 'Loaded parameters in with the wrong priorities');
OAuthTestUtils::build_request('POST', 'http://testbed/test?oauth_foo=get');
$this->assertEquals('get', OAuthRequest::from_request()->get_parameter('oauth_foo'), 'Loaded parameters in with the wrong priorities');
}
public function testNormalizeHttpMethod() {
OAuthTestUtils::build_request('POST', 'http://testbed/test');
$this->assertEquals('POST', OAuthRequest::from_request()->get_normalized_http_method(), 'Failed to normalize HTTP method: POST');
OAuthTestUtils::build_request('post', 'http://testbed/test');
$this->assertEquals('POST', OAuthRequest::from_request()->get_normalized_http_method(), 'Failed to normalize HTTP method: post');
OAuthTestUtils::build_request('GET', 'http://testbed/test');
$this->assertEquals('GET', OAuthRequest::from_request()->get_normalized_http_method(), 'Failed to normalize HTTP method: GET');
OAuthTestUtils::build_request('PUT', 'http://testbed/test');
$this->assertEquals('PUT', OAuthRequest::from_request()->get_normalized_http_method(), 'Failed to normalize HTTP method: PUT');
}
public function testNormalizeParameters() {
// This is mostly repeats of OAuthUtilTest::testParseParameters & OAuthUtilTest::TestBuildHttpQuery
// Tests taken from
// http://wiki.oauth.net/TestCases ("Normalize Request Parameters")
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'name');
$this->assertEquals( 'name=', OAuthRequest::from_request()->get_signable_parameters());
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'a=b');
$this->assertEquals( 'a=b', OAuthRequest::from_request()->get_signable_parameters());
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'a=b&c=d');
$this->assertEquals( 'a=b&c=d', OAuthRequest::from_request()->get_signable_parameters());
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'a=x%21y&a=x+y');
$this->assertEquals( 'a=x%20y&a=x%21y', OAuthRequest::from_request()->get_signable_parameters());
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'x%21y=a&x=a');
$this->assertEquals( 'x=a&x%21y=a', OAuthRequest::from_request()->get_signable_parameters());
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'a=1&c=hi there&f=25&f=50&f=a&z=p&z=t');
$this->assertEquals( 'a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t', OAuthRequest::from_request()->get_signable_parameters());
}
public function testNormalizeHttpUrl() {
OAuthTestUtils::build_request('POST', 'http://example.com');
$this->assertEquals('http://example.com', OAuthRequest::from_request()->get_normalized_http_url());
OAuthTestUtils::build_request('POST', 'https://example.com');
$this->assertEquals('https://example.com', OAuthRequest::from_request()->get_normalized_http_url());
// Tests that http on !80 and https on !443 keeps the port
OAuthTestUtils::build_request('POST', 'http://example.com:8080');
$this->assertEquals('http://example.com:8080', OAuthRequest::from_request()->get_normalized_http_url());
OAuthTestUtils::build_request('POST', 'https://example.com:80');
$this->assertEquals('https://example.com:80', OAuthRequest::from_request()->get_normalized_http_url());
OAuthTestUtils::build_request('POST', 'http://example.com:443');
$this->assertEquals('http://example.com:443', OAuthRequest::from_request()->get_normalized_http_url());
OAuthTestUtils::build_request('POST', 'http://Example.COM');
$this->assertEquals('http://example.com', OAuthRequest::from_request()->get_normalized_http_url());
// Emulate silly behavior by some clients, where there Host header includes the port
OAuthTestUtils::build_request('POST', 'http://example.com');
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'];
$this->assertEquals('http://example.com', OAuthRequest::from_request()->get_normalized_http_url());
}
public function testBuildPostData() {
OAuthTestUtils::build_request('POST', 'http://example.com');
$this->assertEquals('', OAuthRequest::from_request()->to_postdata());
OAuthTestUtils::build_request('POST', 'http://example.com', 'foo=bar');
$this->assertEquals('foo=bar', OAuthRequest::from_request()->to_postdata());
OAuthTestUtils::build_request('GET', 'http://example.com?foo=bar');
$this->assertEquals('foo=bar', OAuthRequest::from_request()->to_postdata());
}
public function testBuildUrl() {
OAuthTestUtils::build_request('POST', 'http://example.com');
$this->assertEquals('http://example.com', OAuthRequest::from_request()->to_url());
OAuthTestUtils::build_request('POST', 'http://example.com', 'foo=bar');
$this->assertEquals('http://example.com?foo=bar', OAuthRequest::from_request()->to_url());
OAuthTestUtils::build_request('GET', 'http://example.com?foo=bar');
$this->assertEquals('http://example.com?foo=bar', OAuthRequest::from_request()->to_url());
}
public function testConvertToString() {
OAuthTestUtils::build_request('POST', 'http://example.com');
$this->assertEquals('http://example.com', (string) OAuthRequest::from_request());
OAuthTestUtils::build_request('POST', 'http://example.com', 'foo=bar');
$this->assertEquals('http://example.com?foo=bar', (string) OAuthRequest::from_request());
OAuthTestUtils::build_request('GET', 'http://example.com?foo=bar');
$this->assertEquals('http://example.com?foo=bar', (string) OAuthRequest::from_request());
}
public function testBuildHeader() {
OAuthTestUtils::build_request('POST', 'http://example.com');
$this->assertEquals('Authorization: OAuth', OAuthRequest::from_request()->to_header());
$this->assertEquals('Authorization: OAuth realm="test"', OAuthRequest::from_request()->to_header('test'));
OAuthTestUtils::build_request('POST', 'http://example.com', 'foo=bar');
$this->assertEquals('Authorization: OAuth', OAuthRequest::from_request()->to_header());
$this->assertEquals('Authorization: OAuth realm="test"', OAuthRequest::from_request()->to_header('test'));
OAuthTestUtils::build_request('POST', 'http://example.com', 'oauth_test=foo');
$this->assertEquals('Authorization: OAuth oauth_test="foo"', OAuthRequest::from_request()->to_header());
$this->assertEquals('Authorization: OAuth realm="test",oauth_test="foo"', OAuthRequest::from_request()->to_header('test'));
// Is headers supposted to be Urlencoded. More to the point:
// Should it be baz = bla,rgh or baz = bla%2Crgh ??
// - morten.fangel
OAuthTestUtils::build_request('POST', 'http://example.com', '', 'OAuth realm="",oauth_foo=bar,oauth_baz="bla,rgh"');
$this->assertEquals('Authorization: OAuth oauth_foo="bar",oauth_baz="bla%2Crgh"', OAuthRequest::from_request()->to_header());
$this->assertEquals('Authorization: OAuth realm="test",oauth_foo="bar",oauth_baz="bla%2Crgh"', OAuthRequest::from_request()->to_header('test'));
}
public function testWontBuildHeaderWithArrayInput() {
$this->setExpectedException('OAuthException');
OAuthTestUtils::build_request('POST', 'http://example.com', 'oauth_foo=bar&oauth_foo=baz');
OAuthRequest::from_request()->to_header();
}
public function testBuildBaseString() {
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'n=v');
$this->assertEquals('POST&http%3A%2F%2Ftestbed%2Ftest&n%3Dv', OAuthRequest::from_request()->get_signature_base_string());
OAuthTestUtils::build_request('POST', 'http://testbed/test', 'n=v&n=v2');
$this->assertEquals('POST&http%3A%2F%2Ftestbed%2Ftest&n%3Dv%26n%3Dv2', OAuthRequest::from_request()->get_signature_base_string());
OAuthTestUtils::build_request('GET', 'http://example.com?n=v');
$this->assertEquals('GET&http%3A%2F%2Fexample.com&n%3Dv', OAuthRequest::from_request()->get_signature_base_string());
$params = 'oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_timestamp=1191242090';
$params .= '&oauth_nonce=hsu94j3884jdopsl&oauth_signature_method=PLAINTEXT&oauth_signature=ignored';
OAuthTestUtils::build_request('POST', 'https://photos.example.net/request_token', $params);
$this->assertEquals('POST&https%3A%2F%2Fphotos.example.net%2Frequest_token&oauth_'
.'consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dhsu94j3884j'
.'dopsl%26oauth_signature_method%3DPLAINTEXT%26oauth_timestam'
.'p%3D1191242090%26oauth_version%3D1.0',
OAuthRequest::from_request()->get_signature_base_string());
$params = 'file=vacation.jpg&size=original&oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03';
$params .= '&oauth_token=nnch734d00sl2jdk&oauth_timestamp=1191242096&oauth_nonce=kllo9940pd9333jh';
$params .= '&oauth_signature=ignored&oauth_signature_method=HMAC-SHA1';
OAuthTestUtils::build_request('GET', 'http://photos.example.net/photos?'.$params);
$this->assertEquals('GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation'
.'.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%'
.'3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26o'
.'auth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jd'
.'k%26oauth_version%3D1.0%26size%3Doriginal',
OAuthRequest::from_request()->get_signature_base_string());
}
public function testBuildSignature() {
$params = 'file=vacation.jpg&size=original&oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03';
$params .= '&oauth_token=nnch734d00sl2jdk&oauth_timestamp=1191242096&oauth_nonce=kllo9940pd9333jh';
$params .= '&oauth_signature=ignored&oauth_signature_method=HMAC-SHA1';
OAuthTestUtils::build_request('GET', 'http://photos.example.net/photos?'.$params);
$r = OAuthRequest::from_request();
$cons = new OAuthConsumer('key', 'kd94hf93k423kf44');
$token = new OAuthToken('token', 'pfkkdhi9sl3r4s00');
$hmac = new OAuthSignatureMethod_HMAC_SHA1();
$plaintext = new OAuthSignatureMethod_PLAINTEXT();
$this->assertEquals('tR3+Ty81lMeYAr/Fid0kMTYa/WM=', $r->build_signature($hmac, $cons, $token));
$this->assertEquals('kd94hf93k423kf44&pfkkdhi9sl3r4s00', $r->build_signature($plaintext, $cons, $token));
}
public function testSign() {
$params = 'file=vacation.jpg&size=original&oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03';
$params .= '&oauth_token=nnch734d00sl2jdk&oauth_timestamp=1191242096&oauth_nonce=kllo9940pd9333jh';
$params .= '&oauth_signature=__ignored__&oauth_signature_method=HMAC-SHA1';
OAuthTestUtils::build_request('GET', 'http://photos.example.net/photos?'.$params);
$r = OAuthRequest::from_request();
$cons = new OAuthConsumer('key', 'kd94hf93k423kf44');
$token = new OAuthToken('token', 'pfkkdhi9sl3r4s00');
$hmac = new OAuthSignatureMethod_HMAC_SHA1();
$plaintext = new OAuthSignatureMethod_PLAINTEXT();
// We need to test both what the parameter is, and how the serialized request is..
$r->sign_request($hmac, $cons, $token);
$this->assertEquals('HMAC-SHA1', $r->get_parameter('oauth_signature_method'));
$this->assertEquals('tR3+Ty81lMeYAr/Fid0kMTYa/WM=', $r->get_parameter('oauth_signature'));
$expectedPostdata = 'file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&'
. 'oauth_signature=tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D&oauth_signature_method=HMAC-SHA1&'
. 'oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original';
$this->assertEquals( $expectedPostdata, $r->to_postdata());
$r->sign_request($plaintext, $cons, $token);
$this->assertEquals('PLAINTEXT', $r->get_parameter('oauth_signature_method'));
$this->assertEquals('kd94hf93k423kf44&pfkkdhi9sl3r4s00', $r->get_parameter('oauth_signature'));
$expectedPostdata = 'file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&'
. 'oauth_signature=kd94hf93k423kf44%26pfkkdhi9sl3r4s00&oauth_signature_method=PLAINTEXT&'
. 'oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original';
$this->assertEquals( $expectedPostdata, $r->to_postdata());
}
}
?>

@ -0,0 +1,225 @@
<?php
require_once dirname(__FILE__) . '/common.php';
require_once dirname(__FILE__) . '/Mock_OAuthDataStore.php';
/**
* Tests of OAuthUtil
*/
class OAuthServerTest extends PHPUnit_Framework_TestCase {
private $consumer;
private $request_token;
private $access_token;
private $hmac_sha1;
private $plaintext;
private $server;
public function setUp() {
$this->consumer = new OAuthConsumer('key', 'secret');
$this->request_token = new OAuthToken('requestkey', 'requestsecret');
$this->access_token = new OAuthToken('accesskey', 'accesssecret');
$this->hmac_sha1 = new OAuthSignatureMethod_HMAC_SHA1();
$this->plaintext = new OAuthSignatureMethod_PLAINTEXT();
$this->server = new OAuthServer( new Mock_OAuthDataStore() );
$this->server->add_signature_method( $this->hmac_sha1 );
$this->server->add_signature_method( $this->plaintext );
}
public function testAcceptValidRequest() {
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
list($consumer, $token) = $this->server->verify_request( $request );
$this->assertEquals( $this->consumer, $consumer );
$this->assertEquals( $this->access_token, $token );
$request->sign_request( $this->hmac_sha1, $this->consumer, $this->access_token );
list($consumer, $token) = $this->server->verify_request( $request );
$this->assertEquals( $this->consumer, $consumer );
$this->assertEquals( $this->access_token, $token );
}
public function testAcceptRequestWithoutVersion() {
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->unset_parameter('oauth_version');
$request->sign_request( $this->hmac_sha1, $this->consumer, $this->access_token );
$this->server->verify_request( $request );
}
public function testRejectRequestSignedWithRequestToken() {
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->request_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->request_token );
$this->setExpectedException('OAuthException');
$this->server->verify_request( $request );
}
public function testRejectRequestWithMissingParameters() {
// The list of required parameters is taken from
// Chapter 7 ("Accessing Protected Resources")
$required_parameters = array(
'oauth_consumer_key',
'oauth_token',
'oauth_signature_method',
'oauth_signature',
'oauth_timestamp',
'oauth_nonce'
);
foreach( $required_parameters AS $required ) {
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
try {
$request->unset_parameter( $required );
$this->server->verify_request($request);
$this->fail('Allowed a request without `' . $required . '`');
} catch( OAuthException $e ) { /* expected */ }
}
}
public function testRejectPastTimestamp() {
// We change the timestamp to be 10 hours ago, it should throw an exception
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->set_parameter( 'oauth_timestamp', $request->get_parameter('oauth_timestamp') - 10*60*60, false);
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
$this->setExpectedException('OAuthException');
$this->server->verify_request($request);
}
public function testRejectFutureTimestamp() {
// We change the timestamp to be 10 hours in the future, it should throw an exception
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->set_parameter( 'oauth_timestamp', $request->get_parameter('oauth_timestamp') + 10*60*60, false);
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
$this->setExpectedException('OAuthException');
$this->server->verify_request($request);
}
public function testRejectUsedNonce() {
// We give a known nonce and should see an exception
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
// The Mock datastore is set to say that the `nonce` nonce is known
$request->set_parameter( 'oauth_nonce', 'nonce', false);
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
$this->setExpectedException('OAuthException');
$this->server->verify_request($request);
}
public function testRejectInvalidSignature() {
// We change the signature post-signing to be something invalid
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
$request->set_parameter( 'oauth_signature', '__whatever__', false);
$this->setExpectedException('OAuthException');
$this->server->verify_request($request);
}
public function testRejectInvalidConsumer() {
// We use the consumer-key "unknown", which isn't known by the datastore.
$unknown_consumer = new OAuthConsumer('unknown', '__unused__');
$request = OAuthRequest::from_consumer_and_token( $unknown_consumer, $this->access_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $unknown_consumer, $this->access_token );
$this->setExpectedException('OAuthException');
$this->server->verify_request( $request );
}
public function testRejectInvalidToken() {
// We use the access-token "unknown" which isn't known by the datastore
$unknown_token = new OAuthToken('unknown', '__unused__');
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $unknown_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $unknown_token );
$this->setExpectedException('OAuthException');
$this->server->verify_request( $request );
}
public function testRejectUnknownSignatureMethod() {
// We use a server that only supports HMAC-SHA1, but requests with PLAINTEXT signature
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
$server = new OAuthServer( new Mock_OAuthDataStore() );
$server->add_signature_method( $this->hmac_sha1 );
$this->setExpectedException('OAuthException');
$server->verify_request( $request );
}
public function testRejectUnknownVersion() {
// We use the version "1.0a" which isn't "1.0", so reject the request
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
$request->set_parameter('oauth_version', '1.0a', false);
$this->setExpectedException('OAuthException');
$this->server->verify_request( $request );
}
public function testCreateRequestToken() {
// We request a new Request Token
$request = OAuthRequest::from_consumer_and_token( $this->consumer, NULL, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, NULL );
$token = $this->server->fetch_request_token($request);
$this->assertEquals($this->request_token, $token);
}
public function testRejectSignedRequestTokenRequest() {
// We request a new Request Token, but the request is signed with a token which should fail
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->request_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->request_token );
$this->setExpectedException('OAuthException');
$token = $this->server->fetch_request_token($request);
}
public function testCreateAccessToken() {
// We request a new Access Token
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->request_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->request_token );
$token = $this->server->fetch_access_token($request);
$this->assertEquals($this->access_token, $token);
}
public function testRejectUnsignedAccessTokenRequest() {
// We request a new Access Token, but we didn't sign the request with a Access Token
$request = OAuthRequest::from_consumer_and_token( $this->consumer, NULL, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, NULL );
$this->setExpectedException('OAuthException');
$token = $this->server->fetch_access_token($request);
}
public function testRejectAccessTokenSignedAccessTokenRequest() {
// We request a new Access Token, but the request is signed with an access token, so fail!
$request = OAuthRequest::from_consumer_and_token( $this->consumer, $this->access_token, 'POST', 'http://example.com');
$request->sign_request( $this->plaintext, $this->consumer, $this->access_token );
$this->setExpectedException('OAuthException');
$token = $this->server->fetch_access_token($request);
}
}

@ -0,0 +1,60 @@
<?php
require_once 'common.php';
require_once 'Mock_OAuthBaseStringRequest.php';
class OAuthSignatureMethodHmacSha1Test extends PHPUnit_Framework_TestCase {
private $method;
public function setUp() {
$this->method = new OAuthSignatureMethod_HMAC_SHA1();
}
public function testIdentifyAsHmacSha1() {
$this->assertEquals('HMAC-SHA1', $this->method->get_name());
}
public function testBuildSignature() {
// Tests taken from http://wiki.oauth.net/TestCases section 9.2 ("HMAC-SHA1")
$request = new Mock_OAuthBaseStringRequest('bs');
$consumer = new OAuthConsumer('__unused__', 'cs');
$token = NULL;
$this->assertEquals('egQqG5AJep5sJ7anhXju1unge2I=', $this->method->build_signature( $request, $consumer, $token) );
$request = new Mock_OAuthBaseStringRequest('bs');
$consumer = new OAuthConsumer('__unused__', 'cs');
$token = new OAuthToken('__unused__', 'ts');
$this->assertEquals('VZVjXceV7JgPq/dOTnNmEfO0Fv8=', $this->method->build_signature( $request, $consumer, $token) );
$request = new Mock_OAuthBaseStringRequest('GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26'
. 'oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26'
. 'oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal');
$consumer = new OAuthConsumer('__unused__', 'kd94hf93k423kf44');
$token = new OAuthToken('__unused__', 'pfkkdhi9sl3r4s00');
$this->assertEquals('tR3+Ty81lMeYAr/Fid0kMTYa/WM=', $this->method->build_signature( $request, $consumer, $token) );
}
public function testVerifySignature() {
// Tests taken from http://wiki.oauth.net/TestCases section 9.2 ("HMAC-SHA1")
$request = new Mock_OAuthBaseStringRequest('bs');
$consumer = new OAuthConsumer('__unused__', 'cs');
$token = NULL;
$signature = 'egQqG5AJep5sJ7anhXju1unge2I=';
$this->assertTrue( $this->method->check_signature( $request, $consumer, $token, $signature) );
$request = new Mock_OAuthBaseStringRequest('bs');
$consumer = new OAuthConsumer('__unused__', 'cs');
$token = new OAuthToken('__unused__', 'ts');
$signature = 'VZVjXceV7JgPq/dOTnNmEfO0Fv8=';
$this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) );
$request = new Mock_OAuthBaseStringRequest('GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26'
. 'oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26'
. 'oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal');
$consumer = new OAuthConsumer('__unused__', 'kd94hf93k423kf44');
$token = new OAuthToken('__unused__', 'pfkkdhi9sl3r4s00');
$signature = 'tR3+Ty81lMeYAr/Fid0kMTYa/WM=';
$this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) );
}
}

@ -0,0 +1,79 @@
<?php
require_once 'common.php';
require_once 'Mock_OAuthBaseStringRequest.php';
class OAuthSignatureMethodPlaintextTest extends PHPUnit_Framework_TestCase {
private $method;
public function setUp() {
$this->method = new OAuthSignatureMethod_PLAINTEXT();
}
public function testIdentifyAsPlaintext() {
$this->assertEquals('PLAINTEXT', $this->method->get_name());
}
public function testBuildSignature() {
// Tests based on from http://wiki.oauth.net/TestCases section 9.2 ("HMAC-SHA1")
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'cs');
$token = NULL;
$this->assertEquals('cs&', $this->method->build_signature( $request, $consumer, $token) );
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'cs');
$token = new OAuthToken('__unused__', 'ts');
$this->assertEquals('cs&ts', $this->method->build_signature( $request, $consumer, $token) );
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'kd94hf93k423kf44');
$token = new OAuthToken('__unused__', 'pfkkdhi9sl3r4s00');
$this->assertEquals('kd94hf93k423kf44&pfkkdhi9sl3r4s00', $this->method->build_signature( $request, $consumer, $token) );
// Tests taken from Chapter 9.4.1 ("Generating Signature") from the spec
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'djr9rjt0jd78jf88');
$token = new OAuthToken('__unused__', 'jjd999tj88uiths3');
$this->assertEquals('djr9rjt0jd78jf88&jjd999tj88uiths3', $this->method->build_signature( $request, $consumer, $token) );
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'djr9rjt0jd78jf88');
$token = new OAuthToken('__unused__', 'jjd99$tj88uiths3');
$this->assertEquals('djr9rjt0jd78jf88&jjd99%24tj88uiths3', $this->method->build_signature( $request, $consumer, $token) );
}
public function testVerifySignature() {
// Tests based on from http://wiki.oauth.net/TestCases section 9.2 ("HMAC-SHA1")
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'cs');
$token = NULL;
$signature = 'cs&';
$this->assertTrue( $this->method->check_signature( $request, $consumer, $token, $signature) );
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'cs');
$token = new OAuthToken('__unused__', 'ts');
$signature = 'cs&ts';
$this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) );
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'kd94hf93k423kf44');
$token = new OAuthToken('__unused__', 'pfkkdhi9sl3r4s00');
$signature = 'kd94hf93k423kf44&pfkkdhi9sl3r4s00';
$this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) );
// Tests taken from Chapter 9.4.1 ("Generating Signature") from the spec
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'djr9rjt0jd78jf88');
$token = new OAuthToken('__unused__', 'jjd999tj88uiths3');
$signature = 'djr9rjt0jd78jf88&jjd999tj88uiths3';
$this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) );
$request = new Mock_OAuthBaseStringRequest('__unused__');
$consumer = new OAuthConsumer('__unused__', 'djr9rjt0jd78jf88');
$token = new OAuthToken('__unused__', 'jjd99$tj88uiths3');
$signature = 'djr9rjt0jd78jf88&jjd99%24tj88uiths3';
$this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) );
}
}

@ -0,0 +1,43 @@
<?php
require_once 'common.php';
require_once 'Mock_OAuthBaseStringRequest.php';
require_once 'Mock_OAuthSignatureMethod_RSA_SHA1.php';
class OAuthSignatureMethodRsaSha1Test extends PHPUnit_Framework_TestCase {
private $method;
public function setUp() {
$this->method = new Mock_OAuthSignatureMethod_RSA_SHA1();
}
public function testIdentifyAsRsaSha1() {
$this->assertEquals('RSA-SHA1', $this->method->get_name());
}
public function testBuildSignature() {
if( ! function_exists('openssl_get_privatekey') ) {
$this->markTestSkipped('OpenSSL not available, can\'t test RSA-SHA1 functionality');
}
// Tests taken from http://wiki.oauth.net/TestCases section 9.3 ("RSA-SHA1")
$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');
$consumer = new OAuthConsumer('dpf43f3p2l4k3l03', '__unused__');
$token = NULL;
$signature = 'jvTp/wX1TYtByB1m+Pbyo0lnCOLIsyGCH7wke8AUs3BpnwZJtAuEJkvQL2/9n4s5wUmUl4aCI4BwpraNx4RtEXMe5qg5T1LVTGliMRpKasKsW//e+RinhejgCuzoH26dyF8iY2ZZ/5D1ilgeijhV/vBka5twt399mXwaYdCwFYE=';
$this->assertEquals($signature, $this->method->build_signature( $request, $consumer, $token) );
}
public function testVerifySignature() {
if( ! function_exists('openssl_get_privatekey') ) {
$this->markTestSkipped('OpenSSL not available, can\'t test RSA-SHA1 functionality');
}
// Tests taken from http://wiki.oauth.net/TestCases section 9.3 ("RSA-SHA1")
$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');
$consumer = new OAuthConsumer('dpf43f3p2l4k3l03', '__unused__');
$token = NULL;
$signature = 'jvTp/wX1TYtByB1m+Pbyo0lnCOLIsyGCH7wke8AUs3BpnwZJtAuEJkvQL2/9n4s5wUmUl4aCI4BwpraNx4RtEXMe5qg5T1LVTGliMRpKasKsW//e+RinhejgCuzoH26dyF8iY2ZZ/5D1ilgeijhV/vBka5twt399mXwaYdCwFYE=';
$this->assertTrue($this->method->check_signature( $request, $consumer, $token, $signature) );
}
}

@ -0,0 +1,20 @@
<?php
require_once 'common.php';
class OAuthTokenTest extends PHPUnit_Framework_TestCase {
public function testSerialize() {
$token = new OAuthToken('token', 'secret');
$this->assertEquals('oauth_token=token&oauth_token_secret=secret', $token->to_string());
$token = new OAuthToken('token&', 'secret%');
$this->assertEquals('oauth_token=token%26&oauth_token_secret=secret%25', $token->to_string());
}
public function testConvertToString() {
$token = new OAuthToken('token', 'secret');
$this->assertEquals('oauth_token=token&oauth_token_secret=secret', (string) $token);
$token = new OAuthToken('token&', 'secret%');
$this->assertEquals('oauth_token=token%26&oauth_token_secret=secret%25', (string) $token);
}
}

@ -0,0 +1,151 @@
<?php
require_once dirname(__FILE__) . '/common.php';
/**
* Tests of OAuthUtil
*/
class OAuthUtilTest extends PHPUnit_Framework_TestCase {
public function testUrlencode() {
// Tests taken from
// http://wiki.oauth.net/TestCases ("Parameter Encoding")
$this->assertEquals('abcABC123', OAuthUtil::urlencode_rfc3986('abcABC123'));
$this->assertEquals('-._~', OAuthUtil::urlencode_rfc3986('-._~'));
$this->assertEquals('%25', OAuthUtil::urlencode_rfc3986('%'));
$this->assertEquals('%2B', OAuthUtil::urlencode_rfc3986('+'));
$this->assertEquals('%0A', OAuthUtil::urlencode_rfc3986("\n"));
$this->assertEquals('%20', OAuthUtil::urlencode_rfc3986(' '));
$this->assertEquals('%7F', OAuthUtil::urlencode_rfc3986("\x7F"));
//$this->assertEquals('%C2%80', OAuthUtil::urlencode_rfc3986("\x00\x80"));
//$this->assertEquals('%E3%80%81', OAuthUtil::urlencode_rfc3986("\x30\x01"));
// Last two checks disabled because of lack of UTF-8 support, or lack
// of knowledge from me (morten.fangel) on how to use it properly..
// A few tests to ensure code-coverage
$this->assertEquals( '', OAuthUtil::urlencode_rfc3986(NULL));
$this->assertEquals( '', OAuthUtil::urlencode_rfc3986(new stdClass()));
}
public function testUrldecode() {
// Tests taken from
// http://wiki.oauth.net/TestCases ("Parameter Encoding")
$this->assertEquals('abcABC123', OAuthUtil::urldecode_rfc3986('abcABC123'));
$this->assertEquals('-._~', OAuthUtil::urldecode_rfc3986('-._~'));
$this->assertEquals('%', OAuthUtil::urldecode_rfc3986('%25'));
$this->assertEquals('+', OAuthUtil::urldecode_rfc3986('%2B'));
$this->assertEquals("\n", OAuthUtil::urldecode_rfc3986('%0A'));
$this->assertEquals(' ', OAuthUtil::urldecode_rfc3986('%20'));
$this->assertEquals("\x7F", OAuthUtil::urldecode_rfc3986('%7F'));
//$this->assertEquals("\x00\x80", OAuthUtil::urldecode_rfc3986('%C2%80'));
//$this->assertEquals("\x30\x01", OAuthUtil::urldecode_rfc3986('%E3%80%81'));
// Last two checks disabled because of lack of UTF-8 support, or lack
// of knowledge from me (morten.fangel) on how to use it properly..
}
public function testParseParameter() {
// Tests taken from
// http://wiki.oauth.net/TestCases ("Normalize Request Parameters")
$this->assertEquals(
array('name'=>''),
OAuthUtil::parse_parameters('name')
);
$this->assertEquals(
array('a'=>'b'),
OAuthUtil::parse_parameters('a=b')
);
$this->assertEquals(
array('a'=>'b','c'=>'d'),
OAuthUtil::parse_parameters('a=b&c=d')
);
$this->assertEquals(
array('a'=>array('x!y','x y')),
OAuthUtil::parse_parameters('a=x!y&a=x+y')
);
$this->assertEquals(
array('x!y'=>'a', 'x' =>'a'),
OAuthUtil::parse_parameters('x!y=a&x=a')
);
}
public function testBuildHttpQuery() {
// Tests taken from
// http://wiki.oauth.net/TestCases ("Normalize Request Parameters")
$this->assertEquals(
'name=',
OAuthUtil::build_http_query(array('name'=>''))
);
$this->assertEquals(
'a=b',
OAuthUtil::build_http_query(array('a'=>'b'))
);
$this->assertEquals(
'a=b&c=d',
OAuthUtil::build_http_query(array('a'=>'b','c'=>'d'))
);
$this->assertEquals(
'a=x%20y&a=x%21y',
OAuthUtil::build_http_query(array('a'=>array('x!y','x y')))
);
$this->assertEquals(
'x=a&x%21y=a',
OAuthUtil::build_http_query(array('x!y'=>'a', 'x' =>'a'))
);
// Test taken from the Spec 9.1.1
$this->assertEquals(
'a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t',
OAuthUtil::build_http_query(array('a'=>'1', 'c' =>'hi there', 'f'=>array(25, 50, 'a'), 'z'=>array('p','t')))
);
// From issue 164, by hidetaka
// Based on discussion at
// http://groups.google.com/group/oauth/browse_thread/thread/7c698004be0d536/dced7b6c82b917b2?lnk=gst&q=sort#
$this->assertEquals(
'x=200&x=25&y=B&y=a',
OAuthUtil::build_http_query(array('x'=>array(25, 200), 'y'=>array('a', 'B')))
);
}
public function testSplitHeader() {
$this->assertEquals(
array('oauth_foo'=>'bar','oauth_baz'=>'bla,rgh'),
OAuthUtil::split_header('OAuth realm="",oauth_foo=bar,oauth_baz="bla,rgh"')
);
$this->assertEquals(
array(),
OAuthUtil::split_header('OAuth realm="",foo=bar,baz="bla,rgh"')
);
$this->assertEquals(
array('foo'=>'bar', 'baz'=>'bla,rgh'),
OAuthUtil::split_header('OAuth realm="",foo=bar,baz="bla,rgh"', false)
);
$this->assertEquals(
array('oauth_foo' => 'hi there'),
OAuthUtil::split_header('OAuth realm="",oauth_foo=hi+there,foo=bar,baz="bla,rgh"')
);
}
public function testGetHeaders() {
if (function_exists('apache_request_headers')) {
$this->markTestSkipped('We assume the apache module is well tested. Since this module is present, no need testing our suplement');
}
$_SERVER['HTTP_HOST'] = 'foo';
$_SERVER['HTTP_X_WHATEVER'] = 'bar';
$this->assertEquals( array('Host'=>'foo', 'X-Whatever'=>'bar'), OAuthUtil::get_headers() );
// Test picking up the Content-Type of POST requests running as an Apache module but not having the ARH method
$_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
$this->assertEquals( array('Host'=>'foo', 'X-Whatever'=>'bar', 'Content-Type'=>'application/x-www-form-urlencoded'), OAuthUtil::get_headers() );
// Test picking up the Content-Type of POST requests when using CGI
unset($_SERVER['CONTENT_TYPE']);
$this->assertEquals( array('Host'=>'foo', 'X-Whatever'=>'bar'), OAuthUtil::get_headers() );
$_ENV['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
$this->assertEquals( array('Host'=>'foo', 'X-Whatever'=>'bar', 'Content-Type'=>'application/x-www-form-urlencoded'), OAuthUtil::get_headers() );
}
}

@ -0,0 +1,60 @@
<?php
require dirname(__FILE__).'/../init.php';
/**
* A simple utils class for methods needed
* during some of the tests
*/
class OAuthTestUtils {
private static function reset_request_vars() {
$_SERVER = array();
$_POST = array();
$_GET = array();
}
/**
* Populates $_{SERVER,GET,POST} and whatever environment-variables needed to test everything..
*
* @param string $method GET or POST
* @param string $uri What URI is the request to (eg http://example.com/foo?bar=baz)
* @param string $post_data What should the post-data be
* @param string $auth_header What to set the Authorization header to
*/
public static function build_request( $method, $uri, $post_data = '', $auth_header = '' ) {
self::reset_request_vars();
$method = strtoupper($method);
$parts = parse_url($uri);
$scheme = $parts['scheme'];
$port = isset( $parts['port'] ) && $parts['port'] ? $parts['port'] : ( $scheme === 'https' ? '443' : '80' );
$host = $parts['host'];
$path = isset( $parts['path'] ) ? $parts['path'] : NULL;
$query = isset( $parts['query'] ) ? $parts['query'] : NULL;
if( $scheme == 'https') {
$_SERVER['HTTPS'] = 'on';
}
$_SERVER['REQUEST_METHOD'] = $method;
$_SERVER['HTTP_HOST'] = $host;
$_SERVER['SERVER_NAME'] = $host;
$_SERVER['SERVER_PORT'] = $port;
$_SERVER['SCRIPT_NAME'] = $path;
$_SERVER['REQUEST_URI'] = $path . '?' . $query;
$_SERVER['QUERY_STRING'] = $query.'';
parse_str($query, $_GET);
if( $method == 'POST' ) {
$_SERVER['HTTP_CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
$_POST = parse_str($post_data);
OAuthRequest::$POST_INPUT = 'data:application/x-www-form-urlencoded,'.$post_data;
}
if( $auth_header != '' ) {
$_SERVER['HTTP_AUTHORIZATION'] = $auth_header;
}
}
}

@ -20,7 +20,7 @@
{{ 'edit.png'|img(22, 'Edit'|get_lang) }}
</a>
</div>
{{ tool.name }}
{{ tool.name|e }}
</li>
{% endfor %}
</ul>
@ -46,7 +46,7 @@
</a>
{% endif %}
</div>
{{ tool.name }}
{{ tool.name|e }}
</li>
{% endfor %}
</ul>

@ -1,43 +1,45 @@
{{ 'ImsLtiDescription'|get_plugin_lang('ImsLtiPlugin') }}
<div class="btn-toolbar">
<a href="{{ _p.web_plugin }}ims_lti/create.php" class="btn btn-primary">
<span class="fa fa-plus fa-fw" aria-hidden="true"></span> {{ 'AddExternalTool'|get_plugin_lang('ImsLtiPlugin') }}
</a>
</div>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>{{ 'Name'|get_lang }}</th>
<th>{{ 'LaunchUrl'|get_plugin_lang('ImsLtiPlugin') }}</th>
<th class="text-center">{{ 'IsGlobal'|get_plugin_lang('ImsLtiPlugin') }}</th>
<th class="text-right">{{ 'Actions'|get_lang }}</th>
</tr>
</thead>
<tbody>
{% for tool in tools %}
{% autoescape 'html' %}
{{ 'ImsLtiDescription'|get_plugin_lang('ImsLtiPlugin') }}
<div class="btn-toolbar">
<a href="{{ _p.web_plugin }}ims_lti/create.php" class="btn btn-primary">
<span class="fa fa-plus fa-fw" aria-hidden="true"></span> {{ 'AddExternalTool'|get_plugin_lang('ImsLtiPlugin') }}
</a>
</div>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<td>{{ tool.name }}</td>
<td>{{ tool.launchUrl }}</td>
<td class="text-center">
{% if tool.isGlobal %}
<span class="fa fa-check-square-o" aria-hidden="true"></span>
<span class="sr-only">{{ 'Yes'|get_lang }}</span>
{% else %}
<span class="fa fa-square-o" aria-hidden="true"></span>
<span class="sr-only">{{ 'No'|get_lang }}</span>
{% endif %}
</td>
<td class="text-right">
<a href="{{ _p.web_plugin }}ims_lti/edit.php?{{ {'id': tool.id}|url_encode() }}" class="btn btn-success">
<span class="fa fa-edit fa-fw" aria-hidden="true"></span> {{ 'Edit'|get_lang }}
</a>
<a href="{{ _p.web_plugin }}ims_lti/delete.php?{{ {'id': tool.id}|url_encode() }}" class="btn btn-danger">
<span class="fa fa-times fa-fw" aria-hidden="true"></span> {{ 'Delete'|get_lang }}
</a>
</td>
<th>{{ 'Name'|get_lang }}</th>
<th>{{ 'LaunchUrl'|get_plugin_lang('ImsLtiPlugin') }}</th>
<th class="text-center">{{ 'IsGlobal'|get_plugin_lang('ImsLtiPlugin') }}</th>
<th class="text-right">{{ 'Actions'|get_lang }}</th>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</thead>
<tbody>
{% for tool in tools %}
<tr>
<td>{{ tool.name }}</td>
<td>{{ tool.launchUrl }}</td>
<td class="text-center">
{% if tool.isGlobal %}
<span class="fa fa-check-square-o" aria-hidden="true"></span>
<span class="sr-only">{{ 'Yes'|get_lang }}</span>
{% else %}
<span class="fa fa-square-o" aria-hidden="true"></span>
<span class="sr-only">{{ 'No'|get_lang }}</span>
{% endif %}
</td>
<td class="text-right">
<a href="{{ _p.web_plugin }}ims_lti/edit.php?{{ {'id': tool.id}|url_encode() }}" class="btn btn-success">
<span class="fa fa-edit fa-fw" aria-hidden="true"></span> {{ 'Edit'|get_lang }}
</a>
<a href="{{ _p.web_plugin }}ims_lti/delete.php?{{ {'id': tool.id}|url_encode() }}" class="btn btn-danger">
<span class="fa fa-times fa-fw" aria-hidden="true"></span> {{ 'Delete'|get_lang }}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endautoescape %}

@ -1,5 +1,5 @@
{% if tool.description %}
<p class="lead">{{ tool.description|nl2br }}</p>
<p class="lead">{{ tool.description|e|nl2br }}</p>
{% endif %}
<div class="embed-responsive embed-responsive-4by3">
<iframe src="{{ launch_url }}" class="plugin-ims-lti-iframe"></iframe>

Loading…
Cancel
Save