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

Conflicts:
	.gitignore
	main/inc/lib/sessionmanager.lib.php
1.10.x
Angel Fernando Quiroz Campos 10 years ago
commit 753edb57d4
  1. 15
      .gitattributes
  2. 4
      .gitignore
  3. 35
      composer.json
  4. 186
      composer.lock
  5. 3
      documentation/changelog.html
  6. 18
      documentation/installation_guide.html
  7. 29
      documentation/optimization.html
  8. 12
      main/admin/usergroup_export.php
  9. 32
      main/admin/usergroup_import.php
  10. 65
      main/announcements/announcements.php
  11. 36
      main/calendar/agenda.lib.php
  12. 12
      main/calendar/agenda.php
  13. 8
      main/calendar/agenda_js.php
  14. 4
      main/calendar/agenda_list.php
  15. 2
      main/chat/chat_functions.lib.php
  16. 2
      main/course_notice/index.php
  17. 4
      main/coursecopy/copy_course_session_selected.php
  18. 172
      main/cron/import_csv.php
  19. 3
      main/cron/user_import/client.php
  20. 10
      main/document/create_audio.php
  21. 36
      main/document/file.php
  22. 6
      main/exercice/export/aiken/aiken_import.inc.php
  23. 25
      main/gradebook/lib/be/studentpublicationlink.class.php
  24. 7
      main/inc/ajax/agenda.ajax.php
  25. 2
      main/inc/ajax/install.ajax.php
  26. 18
      main/inc/autoload.inc.php
  27. 24
      main/inc/global.inc.php
  28. 0
      main/inc/lib/AnnouncementEmail.php
  29. 3
      main/inc/lib/add_course.lib.inc.php
  30. 2
      main/inc/lib/autoload.class.php
  31. 3
      main/inc/lib/certificate.lib.php
  32. 50
      main/inc/lib/course.lib.php
  33. 31
      main/inc/lib/document.lib.php
  34. 73
      main/inc/lib/events.lib.inc.php
  35. 3072
      main/inc/lib/ezpdf/class.pdf.php
  36. 9
      main/inc/lib/formvalidator/FormValidator.class.php
  37. 2
      main/inc/lib/formvalidator/Rule/allowed_tags.inc.php
  38. 1
      main/inc/lib/htmlpurifier/VERSION
  39. 6
      main/inc/lib/htmlpurifier/configdoc/index.html
  40. 6
      main/inc/lib/htmlpurifier/configdoc/styles/index.html
  41. 6
      main/inc/lib/htmlpurifier/extras/ConfigDoc/index.html
  42. 6
      main/inc/lib/htmlpurifier/extras/FSTools/index.html
  43. 6
      main/inc/lib/htmlpurifier/extras/index.html
  44. 6
      main/inc/lib/htmlpurifier/index.html
  45. 23
      main/inc/lib/htmlpurifier/library/HTMLPurifier.func.php
  46. 237
      main/inc/lib/htmlpurifier/library/HTMLPurifier.php
  47. 128
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrCollections.php
  48. 123
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef.php
  49. 21
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php
  50. 87
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php
  51. 133
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php
  52. 43
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php
  53. 78
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php
  54. 38
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php
  55. 28
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php
  56. 54
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php
  57. 149
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php
  58. 72
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php
  59. 40
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php
  60. 47
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php
  61. 78
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php
  62. 58
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php
  63. 69
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php
  64. 40
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php
  65. 38
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php
  66. 52
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php
  67. 6
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/index.html
  68. 65
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php
  69. 28
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php
  70. 34
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php
  71. 32
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php
  72. 21
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php
  73. 70
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php
  74. 41
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php
  75. 53
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php
  76. 41
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php
  77. 52
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php
  78. 48
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php
  79. 6
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/index.html
  80. 73
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php
  81. 73
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php
  82. 34
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php
  83. 15
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php
  84. 77
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php
  85. 17
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php
  86. 21
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php
  87. 6
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/index.html
  88. 68
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php
  89. 39
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php
  90. 99
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php
  91. 6
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/URI/index.html
  92. 6
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrDef/index.html
  93. 56
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrTransform.php
  94. 23
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php
  95. 19
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php
  96. 23
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php
  97. 36
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php
  98. 18
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php
  99. 58
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php
  100. 44
      main/inc/lib/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php
  101. Some files were not shown because too many files have changed in this diff Show More

15
.gitattributes vendored

@ -2,3 +2,18 @@
.gitignore export-ignore
.travis.yml export-ignore
/tests export-ignore
/vendor/ezyang/htmlpurifier/docs export-ignore
/vendor/ezyang/htmlpurifier/benchmarks export-ignore
/vendor/ezyang/htmlpurifier/tests export-ignore
/vendor/ezyang/htmlpurifier/smoketests export-ignore
/vendor/ezyang/htmlpurifier/package.php export-ignore
/vendor/ezyang/htmlpurifier/release1-update.php export-ignore
/vendor/ezyang/htmlpurifier/release2-tag.php export-ignore
/vendor/ezyang/htmlpurifier/test-settings.sample.php export-ignore
/vendor/twig/twig/test export-ignore
/vendor/monolog/monolog/tests/ export-ignore
/vendor/neutron/temporary-filesystem/tests export-ignore
/vendor/sabre/vobject/tests export-ignore
/vendor/twig/twig/test export-ignore
/vendor/symfony/console/Symfony/Component/Console/Tests export-ignore

4
.gitignore vendored

@ -37,4 +37,6 @@ nbproject/*
plugin/bbb/config.vm.php
# Extrafields files
main/upload/extrafields/*
main/upload/extrafields/*
main/cron/incoming/*

@ -1,11 +1,44 @@
{
"name": "chamilo/chamilo-lms",
"description": "E-learning and collaboration software",
"type": "project",
"homepage": "http://www.chamilo.org",
"license": "GPL-3.0",
"support": {
"forum": "http://www.chamilo.org/forum",
"irc": "irc://irc.freenode.org/chamilo"
},
"autoload": {
"classmap": [
"main/auth",
"main/admin",
"main/cron/lang",
"main/coursecopy",
"main/exercice",
"main/gradebook/lib",
"main/newscorm",
"main/inc/lib",
"plugin",
"main/install",
"main/inc/lib/getid3",
"main/survey"
]
},
"require": {
"php": ">=5.3.3",
"php-ffmpeg/php-ffmpeg": "0.3.x-dev@dev",
"sabre/vobject": "~3.1",
"toin0u/digitalocean": "~1.4",
"twig/twig": "1.*",
"michelf/php-markdown": "1.4.1",
"emojione/emojione": "1.3.0",
"zendframework/zend-config": "2.3.3"
"zendframework/zend-config": "2.3.3",
"ezyang/htmlpurifier": "4.6.0",
"aferrandini/phpqrcode": "1.0.1"
},
"extra": {
"branch-alias": {
"dev-master": "1.10.x-dev"
}
}
}

186
composer.lock generated

@ -4,8 +4,52 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "1abe77cf0b8752805b4ac0e3cde352b0",
"hash": "a422c2e4eb5cfff2fa4784fd9036ed9c",
"packages": [
{
"name": "aferrandini/phpqrcode",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/aferrandini/PHPQRCode.git",
"reference": "3c1c0454d43710ab5bbe19a51ad4cb41c22e3d46"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aferrandini/PHPQRCode/zipball/3c1c0454d43710ab5bbe19a51ad4cb41c22e3d46",
"reference": "3c1c0454d43710ab5bbe19a51ad4cb41c22e3d46",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"PHPQRCode": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ariel Ferrandini",
"email": "arielferrandini@gmail.com",
"homepage": "http://www.ferrandini.com/",
"role": "Developer"
}
],
"description": "PHPQRCode porting and changed for PHP 5.3 compatibility",
"homepage": "https://github.com/aferrandini/PHPQRCode",
"keywords": [
"barcode",
"php",
"qrcode"
],
"time": "2013-07-08 09:39:08"
},
{
"name": "alchemy/binary-driver",
"version": "1.5.0",
@ -65,16 +109,16 @@
},
{
"name": "doctrine/cache",
"version": "v1.3.1",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "cf483685798a72c93bf4206e3dd6358ea07d64e7"
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/cf483685798a72c93bf4206e3dd6358ea07d64e7",
"reference": "cf483685798a72c93bf4206e3dd6358ea07d64e7",
"url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8",
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8",
"shasum": ""
},
"require": {
@ -85,6 +129,7 @@
},
"require-dev": {
"phpunit/phpunit": ">=3.7",
"predis/predis": "~0.8",
"satooshi/php-coveralls": "~0.6"
},
"type": "library",
@ -130,7 +175,7 @@
"cache",
"caching"
],
"time": "2014-09-17 14:24:04"
"time": "2015-01-15 20:38:55"
},
{
"name": "emojione/emojione",
@ -210,6 +255,50 @@
],
"time": "2012-05-30 15:01:08"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.6.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "6f389f0f25b90d0b495308efcfa073981177f0fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/6f389f0f25b90d0b495308efcfa073981177f0fd",
"reference": "6f389f0f25b90d0b495308efcfa073981177f0fd",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"type": "library",
"autoload": {
"psr-0": {
"HTMLPurifier": "library/"
},
"files": [
"library/HTMLPurifier.composer.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"time": "2013-11-30 08:25:19"
},
{
"name": "michelf/php-markdown",
"version": "1.4.1",
@ -263,16 +352,16 @@
},
{
"name": "monolog/monolog",
"version": "1.11.0",
"version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "ec3961874c43840e96da3a8a1ed20d8c73d7e5aa"
"reference": "1fbe8c2641f2b163addf49cc5e18f144bec6b19f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/ec3961874c43840e96da3a8a1ed20d8c73d7e5aa",
"reference": "ec3961874c43840e96da3a8a1ed20d8c73d7e5aa",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/1fbe8c2641f2b163addf49cc5e18f144bec6b19f",
"reference": "1fbe8c2641f2b163addf49cc5e18f144bec6b19f",
"shasum": ""
},
"require": {
@ -286,7 +375,7 @@
"aws/aws-sdk-php": "~2.4, >2.4.8",
"doctrine/couchdb": "~1.0@dev",
"graylog2/gelf-php": "~1.0",
"phpunit/phpunit": "~3.7.0",
"phpunit/phpunit": "~4.0",
"raven/raven": "~0.5",
"ruflin/elastica": "0.90.*",
"videlalvaro/php-amqplib": "~2.4"
@ -305,7 +394,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.11.x-dev"
"dev-master": "1.12.x-dev"
}
},
"autoload": {
@ -331,7 +420,7 @@
"logging",
"psr-3"
],
"time": "2014-09-30 13:30:58"
"time": "2014-12-29 21:29:35"
},
{
"name": "neutron/temporary-filesystem",
@ -482,16 +571,16 @@
},
{
"name": "sabre/vobject",
"version": "3.3.4",
"version": "3.3.5",
"source": {
"type": "git",
"url": "https://github.com/fruux/sabre-vobject.git",
"reference": "e7cbc59a7a77325dfa32924865e1802c9216a3e0"
"reference": "77cb636a5bde4c19d7522c2c548b258859ddd1ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/e7cbc59a7a77325dfa32924865e1802c9216a3e0",
"reference": "e7cbc59a7a77325dfa32924865e1802c9216a3e0",
"url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/77cb636a5bde4c19d7522c2c548b258859ddd1ef",
"reference": "77cb636a5bde4c19d7522c2c548b258859ddd1ef",
"shasum": ""
},
"require": {
@ -544,21 +633,21 @@
"jCard",
"vCard"
],
"time": "2014-11-19 22:15:24"
"time": "2015-01-10 00:54:52"
},
{
"name": "symfony/console",
"version": "v2.6.1",
"version": "v2.6.4",
"target-dir": "Symfony/Component/Console",
"source": {
"type": "git",
"url": "https://github.com/symfony/Console.git",
"reference": "ef825fd9f809d275926547c9e57cbf14968793e8"
"reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Console/zipball/ef825fd9f809d275926547c9e57cbf14968793e8",
"reference": "ef825fd9f809d275926547c9e57cbf14968793e8",
"url": "https://api.github.com/repos/symfony/Console/zipball/e44154bfe3e41e8267d7a3794cd9da9a51cfac34",
"reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34",
"shasum": ""
},
"require": {
@ -601,21 +690,21 @@
],
"description": "Symfony Console Component",
"homepage": "http://symfony.com",
"time": "2014-12-02 20:19:20"
"time": "2015-01-25 04:39:26"
},
{
"name": "symfony/filesystem",
"version": "v2.6.1",
"version": "v2.6.4",
"target-dir": "Symfony/Component/Filesystem",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem.git",
"reference": "ff6efc95256cb33031933729e68b01d720b5436b"
"reference": "a1f566d1f92e142fa1593f4555d6d89e3044a9b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/ff6efc95256cb33031933729e68b01d720b5436b",
"reference": "ff6efc95256cb33031933729e68b01d720b5436b",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/a1f566d1f92e142fa1593f4555d6d89e3044a9b7",
"reference": "a1f566d1f92e142fa1593f4555d6d89e3044a9b7",
"shasum": ""
},
"require": {
@ -648,21 +737,21 @@
],
"description": "Symfony Filesystem Component",
"homepage": "http://symfony.com",
"time": "2014-12-02 20:19:20"
"time": "2015-01-03 21:13:09"
},
{
"name": "symfony/process",
"version": "v2.6.1",
"version": "v2.6.4",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
"reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a"
"reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Process/zipball/bf0c9bd625f13b0b0bbe39919225cf145dfb935a",
"reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a",
"url": "https://api.github.com/repos/symfony/Process/zipball/ecfc23e89d9967999fa5f60a1e9af7384396e9ae",
"reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae",
"shasum": ""
},
"require": {
@ -695,21 +784,21 @@
],
"description": "Symfony Process Component",
"homepage": "http://symfony.com",
"time": "2014-12-02 20:19:20"
"time": "2015-01-25 04:39:26"
},
{
"name": "symfony/yaml",
"version": "v2.6.1",
"version": "v2.6.4",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "3346fc090a3eb6b53d408db2903b241af51dcb20"
"reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20",
"reference": "3346fc090a3eb6b53d408db2903b241af51dcb20",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/60ed7751671113cf1ee7d7778e691642c2e9acd8",
"reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8",
"shasum": ""
},
"require": {
@ -742,7 +831,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2014-12-02 20:19:20"
"time": "2015-01-25 04:39:26"
},
{
"name": "toin0u/digitalocean",
@ -866,16 +955,16 @@
},
{
"name": "twig/twig",
"version": "v1.16.2",
"version": "v1.18.0",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Twig.git",
"reference": "42f758d9fe2146d1f0470604fc05ee43580873fc"
"url": "https://github.com/twigphp/Twig.git",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/42f758d9fe2146d1f0470604fc05ee43580873fc",
"reference": "42f758d9fe2146d1f0470604fc05ee43580873fc",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/4cf7464348e7f9893a93f7096a90b73722be99cf",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf",
"shasum": ""
},
"require": {
@ -884,7 +973,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.16-dev"
"dev-master": "1.18-dev"
}
},
"autoload": {
@ -910,7 +999,7 @@
},
{
"name": "Twig Team",
"homepage": "https://github.com/fabpot/Twig/graphs/contributors",
"homepage": "http://twig.sensiolabs.org/contributors",
"role": "Contributors"
}
],
@ -919,7 +1008,7 @@
"keywords": [
"templating"
],
"time": "2014-10-17 12:53:44"
"time": "2015-01-25 17:32:08"
},
{
"name": "zendframework/zend-config",
@ -1035,6 +1124,9 @@
"php-ffmpeg/php-ffmpeg": 20
},
"prefer-stable": false,
"platform": [],
"prefer-lowest": false,
"platform": {
"php": ">=5.3.3"
},
"platform-dev": []
}

@ -101,7 +101,6 @@ All security issues are published and patches are attached on <a href="https://s
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3bc8fd6fad15e6d92e8c1fd32e28d531c8c07d1d">3bc8fd6f</a>) Add $_configuration['document_if_file_exists_option']</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/73e381620438970423d371e717ad0bb8d5667a29">73e38162</a> - <a href="https://task.beeznest.com/issues/9247">BT#9247</a>) Adding exercise_max_fckeditors_in_page setting</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b14bcb36ad2145721205145561ae9a2d024a3a36">b14bcb36</a>) Add option $_configuration['certificate_pdf_orientation']</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6bd4b5df0db53da2e586f1dac514873aca11ba7b">6bd4b5df</a> - <a href="https://task.beeznest.com/issues/8814">BT#8814</a>) Add auto attendance</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7dbed8004f3a7da69a187df1de1cf7034097dfd7">7dbed800</a> - <a href="https://task.beeznest.com/issues/8703">BT#8703</a>) Add hosting total size checker</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/218dc6a4d7f27026b51df142a4b41d944bf44423">218dc6a4</a> - <a href="https://task.beeznest.com/issues/9175">BT#9175</a>) Add hosting_limit_active_courses setting</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1d68db47b2dcb00a36e5b2d90e5be3cd6494cd56">1d68db47</a> - <a href="https://support.chamilo.org/issues/398">#398</a>) Support Opale/Scenarii by adding variable to better support SCORM 1.2 by watching over the definition, by the SCO, of the lesson_status and the call to LMSFinish() or the move to another element</li>
@ -112,7 +111,7 @@ All security issues are published and patches are attached on <a href="https://s
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2db9057d7b589e1d91554f5f39df415c810aeb95">2db9057d</a> - <a href="https://support.chamilo.org/issues/7328">#7328</a>) Add theme_backup and default_template settings</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8d9a82535e9a1f6e11832f8217809d6e8cae9b36">8d9a8253</a>) Add script to check users data in CSV file</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f52df87bded7b10787bec5516124024b5ad4edea">f52df87b</a> - <a href="https://task.beeznest.com/issues/8845">BT#8845</a>) Add script to move users from one course to another depending on them having passed an exam or not</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/27493b32acc9d6cde3e95b5a34e4c03dcc004589">27493b32</a> - <a href="https://support.chamilo.org/issues/7324">#7324</a>) Add possibility to hide recordings to students in conferences list in BBB plugin</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/27493b32acc9d6cde3e95b5a34e4c03dcc004589">27493b32</a> - <a href="https://support.chamilo.org/issues/7324">#7324</a>) Add possibility to hide recordings from students in conferences list in BBB plugin</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c24c758f7469fd73646892f2d37636d158c9fd8a">c24c758f</a> - <a href="https://task.beeznest.com/issues/8840">BT#8840</a>) Add $_configuration['auto_detect_language_custom_pages'] to detect the language in custom pages</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a2ff44cf6978393a3b5577afd408f11d58694c3c">a2ff44cf</a> - <a href="https://support.chamilo.org/issues/7212">#7212</a>) Add calculated answers feature (in beta test)</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/25cd7ddc4928c76591dd983b05abf6a7cf929654">25cd7ddc</a>) Use .gitattributes file to enable special Github features for versions packaging</li>

@ -155,8 +155,7 @@ enable CSS styles package upload and sub-language definition:
<li>[chamilo]/main/css/</li>
<li>[chamilo]/main/lang/</li>
</ul>
Starting from Chamilo 1.8.8, you can also enable full-text indexing features which
require the php5-xapian PHP's extension module to be installed. If you do use
Starting from Chamilo 1.8.8, you can also enable full-text indexing features which require the php5-xapian PHP's extension module to be installed. If you do use
it, you will need to allow your system to write into the sarchdb directory:
<ul>
<li>[chamilo]/searchdb</li>
@ -339,10 +338,8 @@ you upgrade.</em>
providers have developed improved migration procedures that use more memory but
process the upgrades up to 20 times faster. If this is the kind of thing you
need, we highly recommend you contact them (see reference below).</div>
<div class="muted"> NOTE: This version of Chamilo can only be used to upgrade from
smaller versions of Chamilo or Dok€os. For example, you cannot use the normal
upgrade scripts from Chamilo 1.9 to upgrade from Dok€os 2.0. If you need this,
please contact one of the Chamilo Association's official providers &lt;providers@chamilo.org&gt;)</div>
<div class="muted"> NOTE: This version of Chamilo can only be used to upgrade from earlier versions of Chamilo or Dok€os. For example, you cannot use the normal
upgrade scripts from Chamilo 1.9 to upgrade from Dok€os 2.0 (which was born after the split with Chamilo). If you need this, please contact one of the Chamilo Association's <a href="https://chamilo.org/providers">official providers</a>)</div>
<p></p>
@ -357,6 +354,7 @@ As this is only a minor version change from previous 1.10.* versions of Chamilo,
"searchdb" directories from the package before you overwrite the previous
files.</li>
<li> edit the main/inc/conf/configuration.php file: at the en of the file, locate the previous version number (e.g. '1.10.4') and change it to this new version (e.g. '1.10.8')</li>
<li> clean your archive/ directory: take a temporary copy of index.html, delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
<li> you're done! No other upgrade procedure is required</li>
</ul>
@ -370,6 +368,7 @@ As this is only a minor version change from previous 1.10.* versions of Chamilo,
<li> unzip the new files of Chamilo 1.10 over the files of the older version (or unzip the files in one folder and then copy the files from there to the older version's directory)</li>
<li> point your browser on your portal URL + main/install/</li>
<li> choose your language and click&nbsp;<span style="font-style: italic;">Upgrade from 1.8.x/1.9.x</span></li>
<li> clean your archive/ directory: take a temporary copy of index.html, delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
</ul>
<br />
@ -383,6 +382,7 @@ As this is only a minor version change from previous 1.10.* versions of Chamilo,
<li> unzip the new files of Chamilo 1.10 over the files of the older version (or unzip the files in one folder and then copy the files from there to the older version's directory)</li>
<li> point your browser on your portal URL + main/install/</li>
<li> choose your language and click&nbsp;<span style="font-style: italic;">Upgrade from 1.8.x/1.9.x</span></li>
<li> clean your archive/ directory: take a temporary copy of index.html, delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
</ul>
A bunch of Chamilo administrators have reported minor issues with the migration between versions considerably apart (like from Dok€os to Chamilo).
This might include loosing some assignments or forum posts. To avoid any ugly effect on your users, we recommend you first establish a checklist
@ -433,6 +433,7 @@ Chamilo/Dok€os root folder</li>
<li> point your browser on your portal URL</li>
<li> choose your language and click&nbsp;<span style="font-style: italic;">Upgrade from 1.6.x</span> and confirm the
current directory of the old version</li>
<li> clean your archive/ directory: take a temporary copy of index.html, delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
</ul>
<br />
@ -793,8 +794,9 @@ Then go to your administration page -&gt; Configuration settings -&gt; Search
and enable the search tool. Follow the recommendations on the page to get the
complete indexing suite installed. Once you're done, all documents you import
into your Chamilo portal in a recognized format will be indexed and searchable.
Chamilo Administrators training (which you can ask any <a href="http://www.chamilo.org/en/providers">Chamilo's Official
Provider</a> for) include a full review of the full-text search feature.
Chamilo intermediate Administrators training (which you can ask any <a href="http://www.chamilo.org/en/providers">Chamilo's Official Provider</a> for) include a full review of the full-text search feature.</p>
<p class="muted">
Note: Xapian's licensing for the PHP extension is a bit different than what is necessary to enter the Debian repositories, so it has been excluded. You can, however, generate your own package by following the <a href="http://trac.xapian.org/wiki/FAQ/PHP%20Bindings%20Package">packaging instructions on Xapian's wiki</a>.
</p>
<hr style="width: 100%; height: 2px;" />

@ -51,6 +51,7 @@
<li><a href="#9.xsendfile">Speeding file downloads with mod_xsendfile</a></li>
<li><a href="#10.igbinary">IGBinary for faster courses backups and better sessions</a></li>
<li><a href="#11.permissions-check">Removing files download permissions check</a></li>
<li><a href="#12.MySQL-compression">MySQL/MariaDB compression</a></li>
</ol>
<h2><a name="1.Using-XCache"></a>1. Using xCache or APC</h2>
@ -355,12 +356,14 @@ Don't have time or resources to optimize your Chamilo installation yourself? Hir
<img src="http://jigsaw.w3.org/css-validator/images/vcss-blue" style="margin: 1em; float: right;" alt="Valid CSS" />
</a>
<hr />
<h2><a name="7.High-numbers-memory"></a>Memory considerations for high numbers of users</h2>
Some administration scripts *have to* handle lists of all users, and this might have a considerable impact on portals with very high numbers of users. For example, the main/admin/add_users_to_session.php script that handles the registration of users into a specific session, if used with the (non-default) full list of users, will devour about 3KB per user, which, for 100,000 users, translates into the need for around 300MB of RAM just to show this page, and to around 3GB for 1,000,000 users.<br />
This mode is not loaded by default, but could still be selected, leading to a "Fatal error: Allowed memory size ... exhausted" message.<br />
The only non-scripted solution here is to allow for the corresponding amount of RAM for your PHP configuration (<em>memory_limit = 300M</em>) or your specific VirtualHost if you use mod-php5 (<em>php_value memory_limit 300M</em>).<br/>
<hr />
<h2><a name="#8.Avoid-non-fixed-values"></a>Avoiding non-fixed values</h2>
<h2><a name="8.Avoid-non-fixed-values"></a>Avoiding non-fixed values</h2>
Many things in Chamilo are written focusing on the ease of use, even for the administrator. Sometimes, these settings are weighing a little bit more on the system. This is the case, between others, of the mail.conf.php file (being loaded unconditionally) and its CONSTANT "IS_WINDOWS_OS", which is defined by a function call (api_is_windows_os()) at the beginning of main_api.lib.php.
The definition of this constant (which is executed at *every* page load) can easily be avoided, and the only place where it is used inconditionally (mail.conf.php) can be modified to set the line as you expect it (depending on whether you use sendmail/exim or smtp).
@ -373,7 +376,7 @@ $platform_email['SMTP_MAILER'] = 'mail';
</pre>
In fact, the complete loading of mail.conf.php can also be avoided if loaded conditionally (with <i>require_once</i>) when sending an e-mail (which is the only case where it is useful).
<hr />
<h2><a name="#9.xsendfile"></a>Speeding file downloads with mod_xsendfile</h2>
<h2><a name="9.xsendfile"></a>Speeding file downloads with mod_xsendfile</h2>
<p>It might have come to your attention that file downloads through Chamilo might get slow, under default conditions, in particular using Apache 2.</p>
<p>There are several ways to fix this, one of which is removing the .htaccess inside the courses/ directory. This, however, will remove all permissions checks on the files contained in this directory, so... most of the time, not ideal unless your portal is *really* open to the world.</p>
<p>Another technique, revealed to us by <a href="http://stackoverflow.com/users/46594/virtualblackfox">VirtualBlackFox</a> on <a href="http://stackoverflow.com/questions/3697748/fastest-way-to-serve-a-file-using-php">this Stackoverflow post</a>, is to use the X-SendFile module for Apache 2.2+ (other web servers might offer other solutions, or avoid the problem initially).</p>
@ -398,11 +401,13 @@ $_configuration['enable_x_sendfile_headers'] = true;
</pre>
Done! Now your downloads should go substantially faster. This is still a feature in observation. We're not sure the benefits are sufficient, so don't hesitate to let us know in <a href="https://support.chamilo.org/issues/6853">the related issue in Chamilo's tracking system</a>
</p>
<h2><a name="#10.igbinary"></a>IGBinary for courses backups and better sessions management</h2>
<hr />
<h2><a name="10.igbinary"></a>IGBinary for courses backups and better sessions management</h2>
<p>
<a href="http://pecl.php.net/package/igbinary">IGBinary</a> is a small PECL library that replaces the PHP serializer. It uses less space (so less memory for serialized objects) and is particularly efficient with memory-based storages (like Memcached). Use it for course backups (see <a href="https://support.chamilo.org/issues/4443">issue 4443</a>) or <a href="http://www.neanderthal-technology.com/2011/11/ubuntu-10-install-php-memcached-with-igbinary-support/">to boost sessions management</a>.
</p>
<h2><a name="#11.permissions-check"></a>Removing files download permissions check</h2>
<hr />
<h2><a name="11.permissions-check"></a>Removing files download permissions check</h2>
<p>
This measure is not cumulative with mod_xsendfile explained above. It is not *recommended* either, as it removes an important security layer.<br />
<br />
@ -435,13 +440,29 @@ RewriteRule ([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 [QSA
</pre><br />
This is easy, doesn't require a server reload and you should see the results pretty quickly. As mentioned above, if security of your content is an issue, though, you should avoid using this technique.
</p>
<hr />
<h2><a name="12.MySQL-compression"></a>MySQL/MariaDB compression</h2>
<p>
If your database server is separate from your web server, you have to play with bandwidth, firewalls, and network restrictions in general.<br />
In particular, when dealing with large-scale portals, the time a SQL query will take to return to the web server will take longer and, eventually, in the most critical cases, will take <b>too long</b>, and your web servers will be completely overloaded (load average very high because the system is waiting for I/O operations, but processors usage not being very high is a clear sign of this).<br />
To solve this kind of issues, MySQL and MariaDB offer a data compression mechanism, which will reduce the amount of data passed between PHP and the database server. Ultimately, this reduction will lower bandwidth usage and reduce the impact of numerous and heavy data requests (and save you).<br />
In 1.10.0, we have added the possibility to enable this compression very easily, from the configuration.php file, uncommenting the following line:
<pre>
//$_configuration['db_client_flags'] = MYSQL_CLIENT_COMPRESS;
</pre>
This should have an immediate effect on the load average on your server.
</p>
<hr />
<h2>Authors</h2>
<ul>
<li>Yannick Warnier, Zend Certified PHP Engineer, BeezNest Belgium SPRL, <a href="mailto:ywarnier@beeznest.net">ywarnier@beeznest.net</a></li>
</ul>
<hr />
Don't have time or resources to optimize your Chamilo installation yourself? Hire an <a href="http://www.chamilo.org/en/providers">official Chamilo provider</a> and get it sorted out professionally by specialists.
<a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10-blue" alt="Valid XHTML 1.0 Transitional" style="margin: 1em; float: right;" height="31" width="88" /></a>
<a href="http://jigsaw.w3.org/css-validator/">
<img src="http://jigsaw.w3.org/css-validator/images/vcss-blue" style="margin: 1em; float: right;" alt="Valid CSS" />
</a>
</div>
</body>
</html>

@ -1,11 +1,10 @@
<?php
/* For licensing terms, see /license.txt */
/**
* @package chamilo.admin
*/
/**
* Code
*/
// name of the language file that needs to be included
$language_file = 'admin';
$cidReset = true;
@ -29,14 +28,15 @@ $form->addElement('header', $tool_name);
$form->addElement('style_submit_button', 'submit', get_lang('Export'), 'class="save"');
if ($form->validate()) {
$user_group = new UserGroup;
$header = array(array('id', 'name', 'description'));
$data = $user_group->get_all_for_export();
$userGroup = new UserGroup();
$header = array(array('id', 'name', 'description', 'users'));
$data = $userGroup->getDataToExport();
$data = array_merge($header, $data);
$filename = 'export_classes_'.api_get_local_time();
Export::export_table_csv($data, $filename);
exit;
}
Display :: display_header($tool_name);
$form->display();
Display::display_footer();

@ -1,5 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This tool allows platform admins to add classes by uploading a CSV file
* @todo Add some langvars to DLTT
@ -13,7 +14,7 @@ function validate_data($classes) {
$errors = array();
$usergroup = new UserGroup();
foreach ($classes as $index => $class) {
// 1. Check wheter ClassName is available.
// 1. Check of class name is available.
if (!isset($class['name']) || strlen(trim($class['name'])) == 0) {
$class['line'] = $index + 2;
$class['error'] = get_lang('MissingClassName');
@ -41,15 +42,34 @@ function validate_data($classes) {
*/
function save_data($classes)
{
$number_of_added_classes = 0;
$count = 0;
$usergroup = new UserGroup();
foreach ($classes as $index => $class) {
$usersToAdd = isset($class['users']) ? $class['users'] : null;
unset($class['users']);
$id = $usergroup->save($class);
if ($id) {
$number_of_added_classes++;
if (!empty($usersToAdd)) {
$usersToAddList = explode(',', $usersToAdd);
$userIdList = array();
foreach ($usersToAddList as $username) {
$userInfo = api_get_user_info_from_username($username);
$userIdList[] = $userInfo['user_id'];
}
if (!empty($userIdList)) {
$usergroup->subscribe_users_to_usergroup(
$id,
$userIdList,
false
);
}
}
$count++;
}
}
return $number_of_added_classes;
return $count;
}
// Language files that should be included.
@ -113,8 +133,8 @@ $form->display();
<p><?php echo get_lang('CSVMustLookLike') . ' (' . get_lang('MandatoryFields') . ')'; ?> :</p>
<pre>
<b>name;description</b>
"User group 1";"Description"
<b>name;description;</b>users
"User group 1";"Description";admin,username1,username2
</pre>
<?php
// Displaying the footer.

@ -220,7 +220,6 @@ if (api_is_allowed_to_edit(false,true) OR
// tooledit : visibility = 2 : only visible for platform administrator
if ($ctok == $_GET['sec_token']) {
AnnouncementManager::delete_announcement($_course, $id);
//delete_added_resource("Ad_Valvas", $delete);
$id = null;
$emailTitle = null;
@ -263,7 +262,7 @@ if (api_is_allowed_to_edit(false,true) OR
$id = intval($_GET['id']);
if (!api_is_course_coach() || api_is_element_in_the_session(TOOL_ANNOUNCEMENT, $id)) {
$sql="SELECT * FROM $tbl_announcement WHERE c_id = $course_id AND id = '$id'";
$sql = "SELECT * FROM $tbl_announcement WHERE c_id = $course_id AND id = '$id'";
$rs = Database::query($sql);
$myrow = Database::fetch_array($rs);
$last_id = $id;
@ -326,7 +325,6 @@ if (api_is_allowed_to_edit(false,true) OR
while (list ($announcementId, $announcementOrder) = Database::fetch_row($result)) {
// STEP 2 : FOUND THE NEXT ANNOUNCEMENT ID AND ORDER.
// COMMIT ORDER SWAP ON THE DB
if ($thisAnnouncementOrderFound) {
$nextAnnouncementId = $announcementId;
$nextAnnouncementOrder = $announcementOrder;
@ -471,7 +469,7 @@ if (api_is_allowed_to_edit(false,true)) {
} else {
// students only get to see the visible announcements
if (empty($_GET['origin']) or $_GET['origin'] !== 'learnpath') {
$group_memberships=GroupManager::get_group_ids($_course['real_id'], $_user['user_id']);
$group_memberships = GroupManager::get_group_ids($_course['real_id'], $_user['user_id']);
if ((api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous())) {
@ -494,19 +492,19 @@ if (api_is_allowed_to_edit(false,true)) {
// the user is member of several groups => display personal announcements AND his group announcements AND the general announcements
if (is_array($group_memberships) && count($group_memberships)>0) {
$sql="SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id
FROM $tbl_announcement announcement, $tbl_item_property ip
WHERE
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref AND
ip.tool='announcement'
AND ip.visibility='1'
$cond_user_id
$condition_session
GROUP BY ip.ref
ORDER BY display_order DESC
LIMIT 0,$maximum";
$sql = "SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id
FROM $tbl_announcement announcement, $tbl_item_property ip
WHERE
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref AND
ip.tool='announcement'
AND ip.visibility='1'
$cond_user_id
$condition_session
GROUP BY ip.ref
ORDER BY display_order DESC
LIMIT 0, $maximum";
} else {
// the user is not member of any group
// this is an identified user => show the general announcements AND his personal announcements
@ -520,16 +518,16 @@ if (api_is_allowed_to_edit(false,true)) {
$sql="SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id
FROM $tbl_announcement announcement, $tbl_item_property ip
WHERE
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref
AND ip.tool='announcement'
AND ip.visibility='1'
$cond_user_id
$condition_session
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref
AND ip.tool='announcement'
AND ip.visibility='1'
$cond_user_id
$condition_session
GROUP BY ip.ref
ORDER BY display_order DESC
LIMIT 0,$maximum";
LIMIT 0, $maximum";
} else {
if (api_get_course_setting('allow_user_edit_announcement')) {
@ -542,13 +540,13 @@ if (api_is_allowed_to_edit(false,true)) {
$sql="SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id
FROM $tbl_announcement announcement, $tbl_item_property ip
WHERE
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref
AND ip.tool='announcement'
AND ip.visibility='1'
AND ip.to_group_id='0'
$condition_session
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref
AND ip.tool='announcement'
AND ip.visibility='1'
AND ip.to_group_id='0'
$condition_session
GROUP BY ip.ref
ORDER BY display_order DESC
LIMIT 0,$maximum";
@ -619,7 +617,6 @@ if ($display_form) {
$title_to_modify = stripslashes($title_to_modify);
// DISPLAY ADD ANNOUNCEMENT COMMAND
//echo '<form method="post" name="f1" enctype = "multipart/form-data" action="'.api_get_self().'?publish_survey='.Security::remove_XSS($surveyid).'&id='.Security::remove_XSS($_GET['id']).'&db_name='.$db_name.'&cidReq='.Security::remove_XSS($_GET['cidReq']).'" style="margin:0px;">';
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
echo '<form class="form-horizontal" method="post" name="f1" enctype = "multipart/form-data" action="'.api_get_self().'?id='.$id.'&'.api_get_cidreq().'" style="margin:0px;">';
if (empty($_GET['id'])) {
@ -668,8 +665,6 @@ if ($display_form) {
$title_to_modify = sprintf(get_lang('RemindInactiveLearnersMailSubject'), api_get_setting('siteName'));
$content_to_modify = get_lang('YourAccountIsActiveYouCanLoginAndCheckYourCourses');
}
} else {
//echo '<span id="recipient_overview">' . get_lang('Everybody') . '</span>';
}
AnnouncementManager::show_to_form($to);
echo ' </div>

@ -16,6 +16,7 @@ class Agenda
public $senderId;
/** @var array */
public $course;
public $comment;
/**
* Constructor
@ -114,6 +115,7 @@ class Agenda
* @param int $parentEventId
* @param array $attachmentArray $_FILES['']
* @param string $attachmentComment
* @param string $eventComment
*
* @return int
*/
@ -127,7 +129,8 @@ class Agenda
$addAsAnnouncement = false,
$parentEventId = null,
$attachmentArray = array(),
$attachmentComment = null
$attachmentComment = null,
$eventComment = null
) {
$start = api_get_utc_datetime($start);
$end = api_get_utc_datetime($end);
@ -160,6 +163,12 @@ class Agenda
'c_id' => $this->course['real_id']
);
$allow = api_get_configuration_value('allow_agenda_event_comment');
if ($allow) {
$attributes['comment'] = $eventComment;
}
if (!empty($parentEventId)) {
$attributes['parent_event_id'] = $parentEventId;
}
@ -533,6 +542,7 @@ class Agenda
* @param int $editRepeatType
* @param array $attachmentArray
* @param string $attachmentComment
* @param string $comment
*
* @return bool
*/
@ -545,7 +555,8 @@ class Agenda
$content,
$usersToSend = array(),
$attachmentArray = array(),
$attachmentComment = null
$attachmentComment = null,
$comment = null
) {
$start = api_get_utc_datetime($start);
$end = api_get_utc_datetime($end);
@ -594,6 +605,12 @@ class Agenda
'all_day' => $allDay
);
$allow = api_get_configuration_value('allow_agenda_event_comment');
if ($allow) {
$attributes['comment'] = $comment;
}
Database::update(
$this->tbl_course_agenda,
$attributes,
@ -1322,6 +1339,7 @@ class Agenda
}
$sql .= $dateCondition;
$allowComments = api_get_configuration_value('allow_agenda_event_comment');
$result = Database::query($sql);
if (Database::num_rows($result)) {
@ -1428,9 +1446,16 @@ class Agenda
$event['parent_event_id'] = $row['parent_event_id'];
$event['has_children'] = $this->hasChildren($row['id'], $course_id) ? 1 : 0;
if ($allowComments) {
$event['comment'] = $row['comment'];
} else {
$event['comment'] = null;
}
$this->events[] = $event;
}
}
return $this->events;
}
@ -1822,6 +1847,11 @@ class Agenda
);
if ($this->type == 'course') {
$allow = api_get_configuration_value('allow_agenda_event_comment');
if ($allow) {
$form->addElement('textarea', 'comment', get_lang('Comment'));
}
$form->addElement('file', 'user_upload', get_lang('AddAnAttachment'));
if ($showAttachmentForm) {
@ -1839,7 +1869,7 @@ class Agenda
}
}
$form->addElement('textarea', 'file_comment', get_lang('Comment'));
$form->addElement('textarea', 'file_comment', get_lang('FileComment'));
}
if (empty($id)) {

@ -114,6 +114,8 @@ if (api_is_allowed_to_edit(false, true) OR
$attachment = $sendAttachment ? $_FILES['user_upload'] : null;
$attachmentComment = isset($values['file_comment']) ? $values['file_comment'] : null;
$comment = isset($values['comment']) ? $values['comment'] : null;
$startDate = $values['date_range_start'];
$endDate = $values['date_range_end'];
@ -127,7 +129,8 @@ if (api_is_allowed_to_edit(false, true) OR
$sendEmail,
null,
$attachment,
$attachmentComment
$attachmentComment,
$comment
);
if (!empty($values['repeat']) && !empty($eventId)) {
@ -174,6 +177,7 @@ if (api_is_allowed_to_edit(false, true) OR
$sendAttachment = isset($_FILES['user_upload']) ? true : false;
$attachment = $sendAttachment ? $_FILES['user_upload'] : null;
$attachmentComment = isset($values['file_comment']) ? $values['file_comment'] : null;
$comment = isset($values['comment']) ? $values['comment'] : null;
// This is a sub event. Delete the current and create another BT#7803
@ -190,7 +194,8 @@ if (api_is_allowed_to_edit(false, true) OR
false,
null,
$attachment,
$attachmentComment
$attachmentComment,
$comment
);
$message = Display::return_message(get_lang('Updated'), 'confirmation');
@ -209,7 +214,8 @@ if (api_is_allowed_to_edit(false, true) OR
$values['content'],
$values['users_to_send'],
$attachment,
$attachmentComment
$attachmentComment,
$comment
);
if (!empty($values['repeat']) && !empty($eventId)) {

@ -1,5 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
/**
* @package chamilo.calendar
*/
@ -221,10 +222,15 @@ $form->addElement('label', get_lang('Date'), '<span id="start_date"></span><span
$form->addElement('text', 'title', get_lang('Title'), array('id' => 'title'));
$form->addElement('textarea', 'content', get_lang('Description'), array('id' => 'content'));
$allowEventComment = api_get_configuration_value('allow_agenda_event_comment');
if ($agenda->type == 'course') {
$form->addElement('html', '<div id="add_as_announcement_div" style="display: none">');
$form->addElement('checkbox', 'add_as_annonuncement', null, get_lang('AddAsAnnouncement'));
$form->addElement('html', '</div>');
if ($allowEventComment) {
$form->addElement('textarea', 'comment', get_lang('Comment'), array('id' => 'comment'));
}
}
$tpl->assign('form_add', $form->return_form());
@ -234,6 +240,8 @@ $content = $tpl->fetch('default/agenda/month.tpl');
$message = Session::read('message');
$tpl->assign('message', $message);
$tpl->assign('allow_agenda_event_comment', $allowEventComment);
Session::erase('message');
$tpl->assign('content', $content);

@ -3,9 +3,7 @@
/**
* @package chamilo.calendar
*/
/**
* INIT SECTION
*/
// name of the language file that needs to be included
$language_file = array('agenda', 'group', 'announcements');

@ -157,7 +157,7 @@ function saveMessage($message, $userId, $_course, $session_id, $group_id, $previ
if (!api_is_anonymous()) {
if (!empty($message)) {
Emojione\Emojione::$imagePathPNG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/png/';
Emojione\Emojione::$imagePathSVG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/svg/';
//Emojione\Emojione::$imagePathSVG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/svg/';
Emojione\Emojione::$ascii = true;
// Parsing emojis

@ -6,7 +6,7 @@
* @license see /license.txt
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
*/
require_once dirname(__FILE__) . '/../inc/autoload.inc.php';
require_once dirname(__FILE__) . '/../../vendor/autoload.php';
$controller = CourseNoticeController::instance();
KeyAuth::enable_services($controller);

@ -8,10 +8,6 @@
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com> Code conventions
* @package chamilo.backup
*/
/**
* Code
*/
/* INIT SECTION */
// Language files that need to be included
$language_file = array('coursebackup', 'admin');

@ -109,7 +109,10 @@ class ImportCsv
$isStatic = strpos($method, 'Static');
if (method_exists($this, $method)) {
if ($method == 'importUnsubscribeStatic' || empty($isStatic)) {
if (($method == 'importUnsubscribeStatic' ||
$method == 'importSubscribeStatic') ||
empty($isStatic)
) {
$fileToProcess[$parts[1]][] = array(
'method' => $method,
'file' => $path.$fileInfo['basename']
@ -144,8 +147,10 @@ class ImportCsv
'teachers',
'courses',
'sessions',
'subscribe-static',
'unsubscribe-static'
);
foreach ($sections as $section) {
$this->logger->addInfo("-- Import $section --");
@ -169,6 +174,7 @@ class ImportCsv
'sessions-static',
'calendar-static',
);
foreach ($sections as $section) {
$this->logger->addInfo("-- Import static files $section --");
@ -644,17 +650,47 @@ class ImportCsv
{
$data = Import::csv_to_array($file);
if ($this->getDumpValues()) {
// Remove all calendar items
$truncateTables = array(
Database::get_course_table(TABLE_AGENDA),
Database::get_course_table(TABLE_AGENDA_ATTACHMENT),
Database::get_course_table(TABLE_AGENDA_REPEAT),
Database::get_course_table(TABLE_AGENDA_REPEAT_NOT),
Database::get_main_table(TABLE_PERSONAL_AGENDA),
Database::get_main_table(TABLE_PERSONAL_AGENDA_REPEAT_NOT),
Database::get_main_table(TABLE_PERSONAL_AGENDA_REPEAT)
);
foreach ($truncateTables as $table) {
$sql = "TRUNCATE $table";
Database::query($sql);
}
$table = Database::get_course_table(TABLE_ITEM_PROPERTY);
$sql = "DELETE FROM $table WHERE tool = 'calendar_event'";
Database::query($sql);
}
if (!empty($data)) {
$this->logger->addInfo(count($data) . " records found.");
$eventsToCreate = array();
$errorFound = false;
foreach ($data as $row) {
$sessionId = SessionManager::get_session_id_from_original_id(
$row['external_sessionID'],
$this->extraFieldIdNameList['session']
);
$sessionId = null;
$externalSessionId = null;
if (isset($row['external_sessionID'])) {
$externalSessionId = $row['external_sessionID'];
$sessionId = SessionManager::get_session_id_from_original_id(
$externalSessionId,
$this->extraFieldIdNameList['session']
);
}
$courseCode = $row['coursecode'];
$courseCode = null;
if (isset($row['coursecode'])) {
$courseCode = $row['coursecode'];
}
$courseInfo = api_get_course_info($courseCode);
if (empty($courseInfo)) {
@ -662,7 +698,7 @@ class ImportCsv
}
if (empty($sessionId)) {
$this->logger->addInfo("external_sessionID: ".$row['external_sessionID']." does not exists.");
$this->logger->addInfo("external_sessionID: ".$externalSessionId." does not exists.");
}
$teacherId = null;
@ -793,6 +829,12 @@ class ImportCsv
$agenda->setSessionId($event['session_id']);
$agenda->setSenderId($event['sender_id']);
$eventComment = $event['comment'];
// To use the event comment you need
// ALTER TABLE c_calendar_event ADD COLUMN comment TEXT;
// add in configuration.php allow_agenda_event_comment = true
if (empty($courseInfo)) {
$this->logger->addInfo(
"No course found for added: #".$event['course_id']." Skipping ..."
@ -814,7 +856,11 @@ class ImportCsv
$event['title'],
$content,
array('everyone'), // send to
false //$addAsAnnouncement = false
false, //$addAsAnnouncement = false
null, // $parentEventId
array(), //$attachmentArray = array(),
null, //$attachmentComment = null,
$eventComment
);
if (!empty($eventId)) {
@ -970,7 +1016,6 @@ class ImportCsv
// 2014-06-30
$dateStart = explode('/', $session['DateStart']);
$dateEnd = explode('/', $session['DateEnd']);
//$visibility = $session['visibility'];
$visibility = $this->defaultSessionVisibility;
$coachId = null;
@ -988,12 +1033,13 @@ class ImportCsv
$dateEnd[0],
$dateEnd[1],
$dateEnd[2],
null, //$session['nb_days_access_before_beginning'],
null, //$session['nb_days_access_after_end'],
$this->daysCoachAccessBeforeBeginning,
$this->daysCoachAccessAfterBeginning,
null,
$coachUserName,
$categoryId,
$visibility
$visibility,
1
);
if (is_numeric($result)) {
@ -1005,6 +1051,28 @@ class ImportCsv
);
}
} else {
$sessionInfo = api_get_session_info($sessionId);
$accessBefore = null;
$accessAfter = null;
if (empty($sessionInfo['nb_days_access_before_beginning']) ||
(!empty($sessionInfo['nb_days_access_before_beginning']) &&
$sessionInfo['nb_days_access_before_beginning'] < $this->daysCoachAccessBeforeBeginning)
) {
$accessBefore = intval($this->daysCoachAccessBeforeBeginning);
}
$accessAfter = null;
if (empty($sessionInfo['nb_days_access_after_end']) ||
(!empty($sessionInfo['nb_days_access_after_end']) &&
$sessionInfo['nb_days_access_after_end'] < $this->daysCoachAccessAfterBeginning)
) {
$accessAfter = intval($this->daysCoachAccessAfterBeginning);
}
$showDescription = isset($sessionInfo['show_description']) ? $sessionInfo['show_description'] : 1;
$result = SessionManager::edit_session(
$sessionId,
$session['SessionName'],
@ -1014,12 +1082,16 @@ class ImportCsv
$dateEnd[0],
$dateEnd[1],
$dateEnd[2],
null,//$session['nb_days_access_before_beginning'],
null,//$session['nb_days_access_after_end'],
$accessBefore,
$accessAfter,
null,
$coachId,
$categoryId,
$visibility
$visibility,
true, //$start_limit =
true, //$end_limit =
null, //$description
$showDescription // $showDescription = null,
);
if (is_numeric($result)) {
@ -1143,7 +1215,10 @@ class ImportCsv
$avoid,
false, // deleteUsersNotInList
false, // updateCourseCoaches
true // sessionWithCoursesModifier
true, // sessionWithCoursesModifier
true, //$addOriginalCourseTeachersAsCourseSessionCoaches
true, //$removeAllTeachersFromCourse
1 // $showDescription
);
if (!empty($result['error_message'])) {
@ -1156,6 +1231,67 @@ class ImportCsv
}
}
/**
* @param string $file
*/
private function importSubscribeStatic($file)
{
$data = Import::csv_reader($file);
if (!empty($data)) {
$this->logger->addInfo(count($data) . " records found.");
foreach ($data as $row) {
$chamiloUserName = $row['UserName'];
$chamiloCourseCode = $row['CourseCode'];
$chamiloSessionId = $row['SessionID'];
$type = $row['Type'];
$sessionInfo = api_get_session_info($chamiloSessionId);
if (empty($sessionInfo)) {
$this->logger->addError('Session does not exists: '.$chamiloSessionId);
continue;
}
$courseInfo = api_get_course_info($chamiloCourseCode);
if (empty($courseInfo)) {
$this->logger->addError('Course does not exists: '.$courseInfo);
continue;
}
$userId = Usermanager::get_user_id_from_username($chamiloUserName);
if (empty($userId)) {
$this->logger->addError('User does not exists: '.$chamiloUserName);
continue;
}
$status = null;
switch ($type) {
case 'student':
SessionManager::subscribe_users_to_session_course(
array($userId),
$chamiloSessionId,
$courseInfo['code'],
null,
false
);
break;
case 'teacher':
SessionManager::set_coach_to_course_session(
$userId,
$chamiloSessionId,
$courseInfo['code']
);
break;
}
$this->logger->addError(
"User '$chamiloUserName' with status $type was added to session: #$chamiloSessionId - Course: " . $courseInfo['code']
);
}
}
}
/**
* @param string $file
*/
@ -1191,7 +1327,9 @@ class ImportCsv
}
CourseManager::unsubscribe_user($userId, $courseInfo['code'], $chamiloSessionId);
$this->logger->addError("User '$chamiloUserName' was removed from session: #$chamiloSessionId, Course: ".$courseInfo['code']);
$this->logger->addError(
"User '$chamiloUserName' was removed from session: #$chamiloSessionId, Course: ".$courseInfo['code']
);
}
}
}

@ -19,9 +19,6 @@ if (php_sapi_name()!='cli') {
die();
}
// include nusoap library
require_once(api_get_path(LIBRARY_PATH).'nusoap/nusoap.php');
// create client
$client = new nusoap_client(api_get_path(WEB_CODE_PATH).'cron/user_import/service.php');

@ -28,7 +28,7 @@ if (api_get_setting('enabled_text2audio') == 'false'){
api_not_allowed(true);
}
$document_data = DocumentManager::get_document_data_by_id($_GET['id'], api_get_course_id());
$document_data = DocumentManager::get_document_data_by_id($_REQUEST['id'], api_get_course_id());
if (empty($document_data)) {
if (api_is_in_group()) {
$group_properties = GroupManager::get_group_properties(api_get_group_id());
@ -212,7 +212,7 @@ $(document).ready(function(){
echo '<div>';
$form = new FormValidator('form1', 'post', null, '', array('id' => 'form1'));
$form->addElement('hidden', 'text2voice_mode', 'google');
$form->addElement('hidden', 'document_id', $document_id);
$form->addElement('hidden', 'id', $document_id);
$form->addElement('text', 'title', get_lang('Title'));
$form->addElement('select', 'lang', get_lang('Language'), $options);
$form->addElement('textarea', 'text', get_lang('InsertText2Audio'), array('id' => 'textarea_google', 'class' =>'span6' ));
@ -235,7 +235,7 @@ $(document).ready(function(){
$form = new FormValidator('form2', 'post', null, '', array('id' => 'form2'));
$form->addElement('hidden', 'text2voice_mode','pediaphon');
$form->addElement('hidden', 'document_id', $document_id);
$form->addElement('hidden', 'id', $document_id);
$form->addElement('text', 'title', get_lang('Title'));
$form->addElement('select', 'lang', get_lang('Language'), $options_pedia, array('onclick' => 'update_voices(this.selectedIndex);'));
$form->addElement('select', 'voices', get_lang('Voice'), array(get_lang('FirstSelectALanguage')), array());
@ -345,7 +345,7 @@ Display :: display_footer();
*/
function downloadMP3_google($filepath, $dir)
{
$location='create_audio.php?'.api_get_cidreq().'&id='.Security::remove_XSS($_POST['document_id']).'&dt2a=google';
$location='create_audio.php?'.api_get_cidreq().'&id='.intval($_POST['id']).'&dt2a=google';
//security
if (!isset($_POST['lang']) && !isset($_POST['text']) && !isset($_POST['title']) && !isset($filepath) && !isset($dir)) {
@ -420,7 +420,7 @@ function downloadMP3_google($filepath, $dir)
* @version january 2011, chamilo 1.8.8
*/
function downloadMP3_pediaphon($filepath, $dir){
$location='create_audio.php?'.api_get_cidreq().'&id='.Security::remove_XSS($_POST['document_id']).'&dt2a=pediaphon';
$location='create_audio.php?'.api_get_cidreq().'&id='.intval($_POST['id']).'&dt2a=pediaphon';
//security
if(!isset($_POST['lang']) && !isset($_POST['text']) && !isset($_POST['title']) && !isset($filepath) && !isset($dir)) {
echo '<script>window.location.href="'.$location.'"</script>';

@ -11,25 +11,25 @@ Use Model\Document;
Use Model\Course;
/**
* Return either
*
* Return either
*
* - one document
* - several documents (file and/or folders) zipped together
*
*
* Used to transfer files to another application through http.
*
*
* Script parameters:
*
* - id id(s) of the document id=1 or id=1,2,4
*
* - id id(s) of the document id=1 or id=1,2,4
* - cidReq course code
*
*
* Note this script enables key authentication so access with a key token is possible.
*
*
* @package chamilo.document
* @license see /license.txt
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
*/
require_once __DIR__ . '/../inc/autoload.inc.php';
require_once __DIR__ . '/../../vendor/autoload.php';
KeyAuth::enable();
require_once __DIR__ . '/../inc/global.inc.php';
@ -48,14 +48,14 @@ $course = Course::current();
/**
* No files requested. We make sure we return 404 error to tell the client
* that the call failed.
* that the call failed.
*/
if (count($ids) == 0 || empty($course)) {
Response::not_found();
}
/**
* One file requested. In this case we return the file itself.
* One file requested. In this case we return the file itself.
*/
if (count($ids) == 1) {
$id = reset($ids);
@ -77,7 +77,7 @@ if (count($ids) == 1) {
}
/**
* Several files requested. In this case we zip them together.
* Several files requested. In this case we zip them together.
*/
$files = array();
$folders = array();
@ -97,9 +97,9 @@ foreach ($ids as $id) {
$requested_folders = $folders;
/**
* Note that if a parent folder is hidden children should not be accesible
* even if they are visible. It is therefore not sufficient to check document
* visibility.
* Note that if a parent folder is hidden children should not be accesible
* even if they are visible. It is therefore not sufficient to check document
* visibility.
*/
while ($folders) {
$items = $folders;
@ -123,7 +123,7 @@ while ($folders) {
$folders = $requested_folders;
/**
* Requested files may not be accessible.
* Requested files may not be accessible.
*/
if (count($files) == 0) {
Response::not_found();
@ -142,7 +142,7 @@ foreach ($items as $item) {
}
/**
* Zip files together.
* Zip files together.
*/
$temp_zip_path = Chamilo::temp_file('zip');
$zip_folder = new PclZip($temp_zip_path);
@ -155,7 +155,7 @@ foreach ($files as $file) {
}
/**
* Send file for download
* Send file for download
*/
event_download(Uri::here());
DocumentManager::file_send_for_download($temp_zip_path, false, get_lang('Documents') . '.zip');

@ -289,11 +289,11 @@ function aiken_parse_file(&$exercise_info, $exercisePath, $file, $questionFile)
$new_question = true;
} else {
if (empty($exercise_info['question'][$question_index]['title'])) {
if (strlen($info) < 40) {
if (strlen($info) < 100) {
$exercise_info['question'][$question_index]['title'] = $info;
} else {
//Question itself (use a 40-chars long title and a larger description)
$exercise_info['question'][$question_index]['title'] = trim(substr($info,0,40)).'...';
//Question itself (use a 100-chars long title and a larger description)
$exercise_info['question'][$question_index]['title'] = trim(substr($info, 0, 100)) . '...';
$exercise_info['question'][$question_index]['description'] = $info;
}
} else {

@ -158,27 +158,32 @@ class StudentPublicationLink extends AbstractLink
public function calc_score($stud_id = null)
{
$stud_id = intval($stud_id);
$tbl_stats = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
$sql = 'SELECT * FROM '.$tbl_stats."
$table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
$sql = 'SELECT * FROM '.$table."
WHERE
c_id = {$this->course_id} AND
id = '".intval($this->get_ref_id())."' AND
session_id = ".api_get_session_id()."";
session_id = ".api_get_session_id()."
"
;
$query = Database::query($sql);
$assignment = Database::fetch_array($query);
if (count($assignment)==0) {
$v_assigment_id ='0';
if (count($assignment) == 0) {
$parentId = '0';
} else {
$v_assigment_id = $assignment['id'];
$parentId = $assignment['id'];
}
$sql = 'SELECT * FROM '.$tbl_stats.'
$sql = 'SELECT * FROM '.$table.'
WHERE
c_id = '.$this->course_id.' AND
active = 1 AND
parent_id ="'.$v_assigment_id.'" AND
session_id='.api_get_session_id().'';
parent_id = "'.$parentId.'" AND
session_id = '.api_get_session_id() .' AND
qualificator_id <> 0
';
if (!empty($stud_id)) {
$sql .= " AND user_id = $stud_id ";
}

@ -36,6 +36,7 @@ switch ($action) {
break;
}
$add_as_announcement = isset($_REQUEST['add_as_annonuncement']) ? $_REQUEST['add_as_annonuncement'] : null;
$comment = isset($_REQUEST['comment']) ? $_REQUEST['comment'] : null;
echo $agenda->add_event(
$_REQUEST['start'],
$_REQUEST['end'],
@ -43,7 +44,11 @@ switch ($action) {
$_REQUEST['title'],
$_REQUEST['content'],
$_REQUEST['users_to_send'],
$add_as_announcement
$add_as_announcement,
null, //$parentEventId = null,
array(), //$attachmentArray = array(),
null, //$attachmentComment = null,
$comment
);
break;
case 'edit_event':

@ -37,8 +37,6 @@ switch ($action) {
} else {
// save contact information with web service
require_once '../lib/nusoap/nusoap.php';
// create a client
$client = new nusoap_client('http://version.chamilo.org/contact.php?wsdl', true);

@ -1,18 +0,0 @@
<?php
/**
* Set up the Chamilo autoload stack. Can be called several time if needed also
* better to avoid it.
*/
require_once dirname(__FILE__) . '/lib/autoload.class.php';
Autoload::register();
/**
use Symfony\Component\ClassLoader\UniversalClassLoader;
$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
'Symfony\\Component\\HttpFoundation', __DIR__.'/vendor/symfony/http-foundation',
));
$loader->register();
*/

@ -84,7 +84,7 @@ if (api_get_setting('login_is_email') == 'true') {
define('USERNAME_MAX_LENGTH', $default_username_length);
// Do not over-use this variable. It is only for this script's local use.
$lib_path = api_get_path(LIBRARY_PATH);
$lib_path = dirname(__FILE__).'/../../main/inc/lib/';
// Fix bug in IIS that doesn't fill the $_SERVER['REQUEST_URI'].
api_request_uri();
@ -96,7 +96,7 @@ ini_set('include_path', api_create_include_path_setting());
ini_set('auto_detect_line_endings', '1');
// Include the libraries that are necessary everywhere
require_once dirname(__FILE__).'/autoload.inc.php';
require_once dirname(__FILE__).'/../../vendor/autoload.php';
require_once $lib_path.'database.lib.php';
require_once $lib_path.'text.lib.php';
@ -115,14 +115,18 @@ if (empty($_configuration['statistics_database']) && $already_installed) {
global $database_connection;
// Connect to the server database and select the main chamilo database.
// When $_configuration['db_persistent_connection'] is set, it is expected to be a boolean type.
if (!($conn_return = @Database::connect(
array(
'server' => $_configuration['db_host'],
'username' => $_configuration['db_user'],
'password' => $_configuration['db_password'],
'persistent' => $_configuration['db_persistent_connection']
)))
) {
$params = array(
'server' => $_configuration['db_host'],
'username' => $_configuration['db_user'],
'password' => $_configuration['db_password'],
'persistent' => $_configuration['db_persistent_connection']
);
// $_configuration['db_client_flags'] can be set in configuration.php to pass
// flags to the DB connection
if (isset($_configuration['db_client_flags']) && !empty($_configuration['db_client_flags'])) {
$params['client_flags'] = $_configuration['db_client_flags'];
}
if (!($conn_return = @Database::connect($params))) {
$global_error_code = 3;
// The database server is not available or credentials are invalid.
require $includePath.'/global_error_message.inc.php';

@ -2015,6 +2015,9 @@ function create_course_tables($course_db_name = null) {
Database::query($sql);
// New course tables for 1.10.x come here
return 0;
}

@ -2,7 +2,7 @@
/**
* Autoload Chamilo classes
*
* @deprecated
* @license see /license.txt
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
*/

@ -261,9 +261,8 @@ class Certificate extends Model
{
//Make sure HTML certificate is generated
if (!empty($text) && !empty($path)) {
require_once api_get_path(LIBRARY_PATH).'phpqrcode/qrlib.php';
//L low, M - Medium, L large error correction
return QRcode::png($text, $path, 'M', 2, 2);
return PHPQRCode\QRcode::png($text, $path, 'M', 2, 2);
}
return false;
}

@ -3603,6 +3603,12 @@ class CourseManager
return $html;
}
/**
* @param string $main_content
* @param string $sub_content
* @param string $sub_sub_content
* @return string
*/
public static function course_item_parent($main_content, $sub_content, $sub_sub_content = null)
{
return '<div class="well">'.$main_content.$sub_content.$sub_sub_content.'</div>';
@ -3615,7 +3621,7 @@ class CourseManager
* in the sense that any user clicking them is registered as a student
* @param int User id
* @param bool Whether to show the document quick-loader or not
* @return void
* @return string
*/
public static function display_special_courses($user_id, $load_dirs = false)
{
@ -3720,7 +3726,7 @@ class CourseManager
* @uses display_courses_in_category() to display the courses themselves
* @param int user id
* @param bool Whether to show the document quick-loader or not
* @return void
* @return string
*/
public static function display_courses($user_id, $load_dirs = false)
{
@ -3758,7 +3764,7 @@ class CourseManager
* class userportal-course-item.
* @param int User category id
* @param bool Whether to show the document quick-loader or not
* @return void
* @return string
*/
public static function display_courses_in_category($user_category_id, $load_dirs = false)
{
@ -3766,7 +3772,7 @@ class CourseManager
// Table definitions
$TABLECOURS = Database :: get_main_table(TABLE_MAIN_COURSE);
$TABLECOURSUSER = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
$TABLE_ACCESS_URL_REL_COURSE = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
$TABLE_ACCESS_URL_REL_COURSE = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
$current_url_id = api_get_current_access_url_id();
// Get course list auto-register
@ -3880,18 +3886,23 @@ class CourseManager
$course_title_url = '';
if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED || $course['status'] == COURSEMANAGER) {
$course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/?id_session=0';
$course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php?id_session=0';
$course_title = Display::url($course_info['title'], $course_title_url);
} else {
$course_title = $course_info['title']." ".Display::tag('span',get_lang('CourseClosed'), array('class'=>'item_closed'));
$course_title = $course_info['title']." ".Display::tag('span', get_lang('CourseClosed'), array('class'=>'item_closed'));
}
// Start displaying the course block itself
if (api_get_setting('display_coursecode_in_courselist') == 'true') {
$course_title .= ' ('.$course_info['visual_code'].') ';
}
if (api_get_setting('display_teacher_in_courselist') == 'true') {
$teachers = CourseManager::get_teacher_list_from_course_code_to_string($course['code'], self::USER_SEPARATOR, true);
$teachers = CourseManager::get_teacher_list_from_course_code_to_string(
$course['code'],
self::USER_SEPARATOR,
true
);
}
$params['link'] = $course_title_url;
@ -3903,11 +3914,11 @@ class CourseManager
$params['notifications'] = $show_notification;
}
$is_subcontent = true;
$isSubcontent = true;
if (empty($user_category_id)) {
$is_subcontent = false;
$isSubcontent = false;
}
$html .= self::course_item_html($params, $is_subcontent);
$html .= self::course_item_html($params, $isSubcontent);
}
return $html;
@ -3932,18 +3943,25 @@ class CourseManager
}
/**
* Get the course id based on the original id and field name in the extra fields. Returns 0 if course was not found
* Get the course id based on the original id and field name in the extra fields.
* Returns 0 if course was not found
*
* @param string Original course code
* @param string Original field name
* @param string $original_course_id_value Original course code
* @param string $original_course_id_name Original field name
* @return int Course id
*/
public static function get_course_id_from_original_id($original_course_id_value, $original_course_id_name)
{
$t_cfv = Database::get_main_table(TABLE_MAIN_COURSE_FIELD_VALUES);
$table_field = Database::get_main_table(TABLE_MAIN_COURSE_FIELD);
$sql_course = "SELECT course_code FROM $table_field cf INNER JOIN $t_cfv cfv ON cfv.field_id=cf.id WHERE field_variable='$original_course_id_name' AND field_value='$original_course_id_value'";
$res = Database::query($sql_course);
$original_course_id_name = Database::escape_string($original_course_id_name);
$original_course_id_name = Database::escape_string($original_course_id_name);
$sql = "SELECT course_code FROM $table_field cf
INNER JOIN $t_cfv cfv ON cfv.field_id=cf.id
WHERE
field_variable='$original_course_id_name' AND
field_value='$original_course_id_value'";
$res = Database::query($sql);
$row = Database::fetch_object($res);
if ($row != false) {
return $row->course_code;
@ -4607,7 +4625,7 @@ class CourseManager
* @param int $url_id
*
*/
public function remove_course_ranking($course_id, $session_id, $url_id = null)
public static function remove_course_ranking($course_id, $session_id, $url_id = null)
{
$table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
$table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);

@ -3223,7 +3223,7 @@ class DocumentManager
if (CourseManager::is_user_subscribed_in_course($user_id, $course_info['code'])) {
$user_in_course = true;
}
//Check if course is open then we can consider that the student is regitered to the course
// Check if course is open then we can consider that the student is registered to the course
if (isset($course_info) && in_array($course_info['visibility'], array(2, 3))) {
$user_in_course = true;
}
@ -3261,6 +3261,13 @@ class DocumentManager
$folderCondition = " AND docs.path LIKE '/%' ";
if (!api_is_allowed_to_edit()) {
$protectedFolders = self::getProtectedFolderFromStudent();
foreach ($protectedFolders as $folder) {
$folderCondition .= " AND docs.path NOT LIKE '$folder' ";
}
}
if ($folderId !== false) {
$parentData = self::get_document_data_by_id($folderId, $course_info['code']);
if (!empty($parentData)) {
@ -3443,7 +3450,6 @@ class DocumentManager
});
}
}
}
</script>";
}
@ -3702,10 +3708,10 @@ class DocumentManager
$overwrite_url
);
}
}
}
}
return $return;
}
@ -4178,9 +4184,9 @@ class DocumentManager
/**
* @return array
*/
static function get_system_folders()
public static function get_system_folders()
{
$system_folders = array(
return array(
'/certificates',
'/HotPotatoes_files',
'/chat_files',
@ -4191,7 +4197,20 @@ class DocumentManager
'/shared_folder',
'/learning_path'
);
return $system_folders;
}
/**
* @return array
*/
public static function getProtectedFolderFromStudent()
{
return array(
'/certificates',
'/HotPotatoes_files',
'/chat_files',
'/shared_folder',
'/learning_path'
);
}
/**

@ -910,40 +910,67 @@ function get_attempt_count_not_finished($user_id, $exerciseId, $lp_id, $lp_item_
*/
function delete_student_lp_events($user_id, $lp_id, $course, $session_id)
{
$lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
$lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
$course_id = $course['real_id'];
$lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
$lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
$lpInteraction = Database::get_course_table(TABLE_LP_IV_INTERACTION);
$lpObjective = Database::get_course_table(TABLE_LP_IV_OBJECTIVE);
$course_id = $course['real_id'];
if (empty($course_id)) {
$course_id = api_get_course_int_id();
}
$track_e_exercises = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
$track_attempts = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
$recording_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
$user_id = intval($user_id);
$lp_id = intval($lp_id);
$session_id = intval($session_id);
$track_e_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
$track_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
$recording_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
$user_id = intval($user_id);
$lp_id = intval($lp_id);
$session_id = intval($session_id);
//Make sure we have the exact lp_view_id
$sql = "SELECT id FROM $lp_view_table
WHERE c_id = $course_id AND user_id = $user_id AND lp_id = $lp_id AND session_id = $session_id ";
$result = Database::query($sql);
WHERE
c_id = $course_id AND
user_id = $user_id AND
lp_id = $lp_id AND
session_id = $session_id ";
$result = Database::query($sql);
if (Database::num_rows($result)) {
$view = Database::fetch_array($result, 'ASSOC');
$lp_view_id = $view['id'];
$sql = "DELETE FROM $lp_item_view_table WHERE c_id = $course_id AND lp_view_id = $lp_view_id ";
$view = Database::fetch_array($result, 'ASSOC');
$lp_view_id = $view['id'];
$sql = "DELETE FROM $lp_item_view_table
WHERE c_id = $course_id AND lp_view_id = $lp_view_id ";
Database::query($sql);
$sql = "DELETE FROM $lpInteraction
WHERE c_id = $course_id AND lp_iv_id = $lp_view_id ";
Database::query($sql);
$sql = "DELETE FROM $lpObjective
WHERE c_id = $course_id AND lp_iv_id = $lp_view_id ";
Database::query($sql);
}
$sql = "DELETE FROM $lp_view_table WHERE c_id = $course_id AND user_id = $user_id AND lp_id= $lp_id AND session_id = $session_id ";
$sql = "DELETE FROM $lp_view_table
WHERE
c_id = $course_id AND
user_id = $user_id AND
lp_id= $lp_id AND
session_id = $session_id
";
Database::query($sql);
$sql = "SELECT exe_id FROM $track_e_exercises
WHERE exe_user_id = $user_id AND session_id = $session_id AND exe_cours_id = '{$course['code']}' AND orig_lp_id = $lp_id";
$result = Database::query($sql);
WHERE
exe_user_id = $user_id AND
session_id = $session_id AND
exe_cours_id = '{$course['code']}' AND
orig_lp_id = $lp_id
";
$result = Database::query($sql);
$exe_list = array();
while ($row = Database::fetch_array($result, 'ASSOC')) {
$exe_list[] = $row['exe_id'];
@ -959,7 +986,15 @@ function delete_student_lp_events($user_id, $lp_id, $course, $session_id)
$sql = "DELETE FROM $recording_table WHERE exe_id IN (".implode(',',$exe_list).")";
Database::query($sql);
}
event_system(LOG_LP_ATTEMPT_DELETE, LOG_LP_ID, $lp_id, null, null, $course['code'], $session_id);
event_system(
LOG_LP_ATTEMPT_DELETE,
LOG_LP_ID,
$lp_id,
null,
null,
$course['code'],
$session_id
);
}
/**

File diff suppressed because it is too large Load Diff

@ -557,12 +557,19 @@ EOT;
* @return string $return_value HTML code of the form
*
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, august 2006
* @author Julio Montoya
*/
public function return_form()
{
$error = false;
$addDateLibraries = false;
$dateElementTypes = array('date_range_picker', 'date_time_picker', 'date_picker', 'datepicker', 'datetimepicker');
$dateElementTypes = array(
'date_range_picker',
'date_time_picker',
'date_picker',
'datepicker',
'datetimepicker'
);
/** @var HTML_QuickForm_element $element */
foreach ($this->_elements as $element) {
if (in_array($element->getType(), $dateElementTypes)) {

@ -921,10 +921,8 @@ $allowed_tags_teacher['body']['link'] = array();
$allowed_tags_teacher['body']['text'] = array();
$allowed_tags_teacher['body']['vlink'] = array();
$allowed_tags_teacher_full_page = $allowed_tags_student_full_page;
// ALLOWED HTML FOR ANONYMOUS USERS
$allowed_tags_anonymous = $allowed_tags_student;

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,23 +0,0 @@
<?php
/**
* @file
* Defines a function wrapper for HTML Purifier for quick use.
* @note ''HTMLPurifier()'' is NOT the same as ''new HTMLPurifier()''
*/
/**
* Purify HTML.
* @param $html String HTML to purify
* @param $config Configuration to use, can be any value accepted by
* HTMLPurifier_Config::create()
*/
function HTMLPurifier($html, $config = null) {
static $purifier = false;
if (!$purifier) {
$purifier = new HTMLPurifier();
}
return $purifier->purify($html, $config);
}
// vim: et sw=4 sts=4

@ -1,237 +0,0 @@
<?php
/*! @mainpage
*
* HTML Purifier is an HTML filter that will take an arbitrary snippet of
* HTML and rigorously test, validate and filter it into a version that
* is safe for output onto webpages. It achieves this by:
*
* -# Lexing (parsing into tokens) the document,
* -# Executing various strategies on the tokens:
* -# Removing all elements not in the whitelist,
* -# Making the tokens well-formed,
* -# Fixing the nesting of the nodes, and
* -# Validating attributes of the nodes; and
* -# Generating HTML from the purified tokens.
*
* However, most users will only need to interface with the HTMLPurifier
* and HTMLPurifier_Config.
*/
/*
HTML Purifier 4.2.0 - Standards Compliant HTML Filtering
Copyright (C) 2006-2008 Edward Z. Yang
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* Facade that coordinates HTML Purifier's subsystems in order to purify HTML.
*
* @note There are several points in which configuration can be specified
* for HTML Purifier. The precedence of these (from lowest to
* highest) is as follows:
* -# Instance: new HTMLPurifier($config)
* -# Invocation: purify($html, $config)
* These configurations are entirely independent of each other and
* are *not* merged (this behavior may change in the future).
*
* @todo We need an easier way to inject strategies using the configuration
* object.
*/
class HTMLPurifier
{
/** Version of HTML Purifier */
public $version = '4.2.0';
/** Constant with version of HTML Purifier */
const VERSION = '4.2.0';
/** Global configuration object */
public $config;
/** Array of extra HTMLPurifier_Filter objects to run on HTML, for backwards compatibility */
private $filters = array();
/** Single instance of HTML Purifier */
private static $instance;
protected $strategy, $generator;
/**
* Resultant HTMLPurifier_Context of last run purification. Is an array
* of contexts if the last called method was purifyArray().
*/
public $context;
/**
* Initializes the purifier.
* @param $config Optional HTMLPurifier_Config object for all instances of
* the purifier, if omitted, a default configuration is
* supplied (which can be overridden on a per-use basis).
* The parameter can also be any type that
* HTMLPurifier_Config::create() supports.
*/
public function __construct($config = null) {
$this->config = HTMLPurifier_Config::create($config);
$this->strategy = new HTMLPurifier_Strategy_Core();
}
/**
* Adds a filter to process the output. First come first serve
* @param $filter HTMLPurifier_Filter object
*/
public function addFilter($filter) {
trigger_error('HTMLPurifier->addFilter() is deprecated, use configuration directives in the Filter namespace or Filter.Custom', E_USER_WARNING);
$this->filters[] = $filter;
}
/**
* Filters an HTML snippet/document to be XSS-free and standards-compliant.
*
* @param $html String of HTML to purify
* @param $config HTMLPurifier_Config object for this operation, if omitted,
* defaults to the config object specified during this
* object's construction. The parameter can also be any type
* that HTMLPurifier_Config::create() supports.
* @return Purified HTML
*/
public function purify($html, $config = null) {
// :TODO: make the config merge in, instead of replace
$config = $config ? HTMLPurifier_Config::create($config) : $this->config;
// implementation is partially environment dependant, partially
// configuration dependant
$lexer = HTMLPurifier_Lexer::create($config);
$context = new HTMLPurifier_Context();
// setup HTML generator
$this->generator = new HTMLPurifier_Generator($config, $context);
$context->register('Generator', $this->generator);
// set up global context variables
if ($config->get('Core.CollectErrors')) {
// may get moved out if other facilities use it
$language_factory = HTMLPurifier_LanguageFactory::instance();
$language = $language_factory->create($config, $context);
$context->register('Locale', $language);
$error_collector = new HTMLPurifier_ErrorCollector($context);
$context->register('ErrorCollector', $error_collector);
}
// setup id_accumulator context, necessary due to the fact that
// AttrValidator can be called from many places
$id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
$context->register('IDAccumulator', $id_accumulator);
$html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context);
// setup filters
$filter_flags = $config->getBatch('Filter');
$custom_filters = $filter_flags['Custom'];
unset($filter_flags['Custom']);
$filters = array();
foreach ($filter_flags as $filter => $flag) {
if (!$flag) continue;
if (strpos($filter, '.') !== false) continue;
$class = "HTMLPurifier_Filter_$filter";
$filters[] = new $class;
}
foreach ($custom_filters as $filter) {
// maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat
$filters[] = $filter;
}
$filters = array_merge($filters, $this->filters);
// maybe prepare(), but later
for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) {
$html = $filters[$i]->preFilter($html, $config, $context);
}
// purified HTML
$html =
$this->generator->generateFromTokens(
// list of tokens
$this->strategy->execute(
// list of un-purified tokens
$lexer->tokenizeHTML(
// un-purified HTML
$html, $config, $context
),
$config, $context
)
);
for ($i = $filter_size - 1; $i >= 0; $i--) {
$html = $filters[$i]->postFilter($html, $config, $context);
}
$html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context);
$this->context =& $context;
return $html;
}
/**
* Filters an array of HTML snippets
* @param $config Optional HTMLPurifier_Config object for this operation.
* See HTMLPurifier::purify() for more details.
* @return Array of purified HTML
*/
public function purifyArray($array_of_html, $config = null) {
$context_array = array();
foreach ($array_of_html as $key => $html) {
$array_of_html[$key] = $this->purify($html, $config);
$context_array[$key] = $this->context;
}
$this->context = $context_array;
return $array_of_html;
}
/**
* Singleton for enforcing just one HTML Purifier in your system
* @param $prototype Optional prototype HTMLPurifier instance to
* overload singleton with, or HTMLPurifier_Config
* instance to configure the generated version with.
*/
public static function instance($prototype = null) {
if (!self::$instance || $prototype) {
if ($prototype instanceof HTMLPurifier) {
self::$instance = $prototype;
} elseif ($prototype) {
self::$instance = new HTMLPurifier($prototype);
} else {
self::$instance = new HTMLPurifier();
}
}
return self::$instance;
}
/**
* @note Backwards compatibility, see instance()
*/
public static function getInstance($prototype = null) {
return HTMLPurifier::instance($prototype);
}
}
// vim: et sw=4 sts=4

@ -1,128 +0,0 @@
<?php
/**
* Defines common attribute collections that modules reference
*/
class HTMLPurifier_AttrCollections
{
/**
* Associative array of attribute collections, indexed by name
*/
public $info = array();
/**
* Performs all expansions on internal data for use by other inclusions
* It also collects all attribute collection extensions from
* modules
* @param $attr_types HTMLPurifier_AttrTypes instance
* @param $modules Hash array of HTMLPurifier_HTMLModule members
*/
public function __construct($attr_types, $modules) {
// load extensions from the modules
foreach ($modules as $module) {
foreach ($module->attr_collections as $coll_i => $coll) {
if (!isset($this->info[$coll_i])) {
$this->info[$coll_i] = array();
}
foreach ($coll as $attr_i => $attr) {
if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
// merge in includes
$this->info[$coll_i][$attr_i] = array_merge(
$this->info[$coll_i][$attr_i], $attr);
continue;
}
$this->info[$coll_i][$attr_i] = $attr;
}
}
}
// perform internal expansions and inclusions
foreach ($this->info as $name => $attr) {
// merge attribute collections that include others
$this->performInclusions($this->info[$name]);
// replace string identifiers with actual attribute objects
$this->expandIdentifiers($this->info[$name], $attr_types);
}
}
/**
* Takes a reference to an attribute associative array and performs
* all inclusions specified by the zero index.
* @param &$attr Reference to attribute array
*/
public function performInclusions(&$attr) {
if (!isset($attr[0])) return;
$merge = $attr[0];
$seen = array(); // recursion guard
// loop through all the inclusions
for ($i = 0; isset($merge[$i]); $i++) {
if (isset($seen[$merge[$i]])) continue;
$seen[$merge[$i]] = true;
// foreach attribute of the inclusion, copy it over
if (!isset($this->info[$merge[$i]])) continue;
foreach ($this->info[$merge[$i]] as $key => $value) {
if (isset($attr[$key])) continue; // also catches more inclusions
$attr[$key] = $value;
}
if (isset($this->info[$merge[$i]][0])) {
// recursion
$merge = array_merge($merge, $this->info[$merge[$i]][0]);
}
}
unset($attr[0]);
}
/**
* Expands all string identifiers in an attribute array by replacing
* them with the appropriate values inside HTMLPurifier_AttrTypes
* @param &$attr Reference to attribute array
* @param $attr_types HTMLPurifier_AttrTypes instance
*/
public function expandIdentifiers(&$attr, $attr_types) {
// because foreach will process new elements we add, make sure we
// skip duplicates
$processed = array();
foreach ($attr as $def_i => $def) {
// skip inclusions
if ($def_i === 0) continue;
if (isset($processed[$def_i])) continue;
// determine whether or not attribute is required
if ($required = (strpos($def_i, '*') !== false)) {
// rename the definition
unset($attr[$def_i]);
$def_i = trim($def_i, '*');
$attr[$def_i] = $def;
}
$processed[$def_i] = true;
// if we've already got a literal object, move on
if (is_object($def)) {
// preserve previous required
$attr[$def_i]->required = ($required || $attr[$def_i]->required);
continue;
}
if ($def === false) {
unset($attr[$def_i]);
continue;
}
if ($t = $attr_types->get($def)) {
$attr[$def_i] = $t;
$attr[$def_i]->required = $required;
} else {
unset($attr[$def_i]);
}
}
}
}
// vim: et sw=4 sts=4

@ -1,123 +0,0 @@
<?php
/**
* Base class for all validating attribute definitions.
*
* This family of classes forms the core for not only HTML attribute validation,
* but also any sort of string that needs to be validated or cleaned (which
* means CSS properties and composite definitions are defined here too).
* Besides defining (through code) what precisely makes the string valid,
* subclasses are also responsible for cleaning the code if possible.
*/
abstract class HTMLPurifier_AttrDef
{
/**
* Tells us whether or not an HTML attribute is minimized. Has no
* meaning in other contexts.
*/
public $minimized = false;
/**
* Tells us whether or not an HTML attribute is required. Has no
* meaning in other contexts
*/
public $required = false;
/**
* Validates and cleans passed string according to a definition.
*
* @param $string String to be validated and cleaned.
* @param $config Mandatory HTMLPurifier_Config object.
* @param $context Mandatory HTMLPurifier_AttrContext object.
*/
abstract public function validate($string, $config, $context);
/**
* Convenience method that parses a string as if it were CDATA.
*
* This method process a string in the manner specified at
* <http://www.w3.org/TR/html4/types.html#h-6.2> by removing
* leading and trailing whitespace, ignoring line feeds, and replacing
* carriage returns and tabs with spaces. While most useful for HTML
* attributes specified as CDATA, it can also be applied to most CSS
* values.
*
* @note This method is not entirely standards compliant, as trim() removes
* more types of whitespace than specified in the spec. In practice,
* this is rarely a problem, as those extra characters usually have
* already been removed by HTMLPurifier_Encoder.
*
* @warning This processing is inconsistent with XML's whitespace handling
* as specified by section 3.3.3 and referenced XHTML 1.0 section
* 4.7. However, note that we are NOT necessarily
* parsing XML, thus, this behavior may still be correct. We
* assume that newlines have been normalized.
*/
public function parseCDATA($string) {
$string = trim($string);
$string = str_replace(array("\n", "\t", "\r"), ' ', $string);
return $string;
}
/**
* Factory method for creating this class from a string.
* @param $string String construction info
* @return Created AttrDef object corresponding to $string
*/
public function make($string) {
// default implementation, return a flyweight of this object.
// If $string has an effect on the returned object (i.e. you
// need to overload this method), it is best
// to clone or instantiate new copies. (Instantiation is safer.)
return $this;
}
/**
* Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work
* properly. THIS IS A HACK!
*/
protected function mungeRgb($string) {
return preg_replace('/rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)/', 'rgb(\1,\2,\3)', $string);
}
/**
* Parses a possibly escaped CSS string and returns the "pure"
* version of it.
*/
protected function expandCSSEscape($string) {
// flexibly parse it
$ret = '';
for ($i = 0, $c = strlen($string); $i < $c; $i++) {
if ($string[$i] === '\\') {
$i++;
if ($i >= $c) {
$ret .= '\\';
break;
}
if (ctype_xdigit($string[$i])) {
$code = $string[$i];
for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) {
if (!ctype_xdigit($string[$i])) break;
$code .= $string[$i];
}
// We have to be extremely careful when adding
// new characters, to make sure we're not breaking
// the encoding.
$char = HTMLPurifier_Encoder::unichr(hexdec($code));
if (HTMLPurifier_Encoder::cleanUTF8($char) === '') continue;
$ret .= $char;
if ($i < $c && trim($string[$i]) !== '') $i--;
continue;
}
if ($string[$i] === "\n") continue;
}
$ret .= $string[$i];
}
return $ret;
}
}
// vim: et sw=4 sts=4

@ -1,21 +0,0 @@
<?php
class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number
{
public function __construct() {
parent::__construct(false); // opacity is non-negative, but we will clamp it
}
public function validate($number, $config, $context) {
$result = parent::validate($number, $config, $context);
if ($result === false) return $result;
$float = (float) $result;
if ($float < 0.0) $result = '0';
if ($float > 1.0) $result = '1';
return $result;
}
}
// vim: et sw=4 sts=4

@ -1,87 +0,0 @@
<?php
/**
* Validates shorthand CSS property background.
* @warning Does not support url tokens that have internal spaces.
*/
class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
{
/**
* Local copy of component validators.
* @note See HTMLPurifier_AttrDef_Font::$info for a similar impl.
*/
protected $info;
public function __construct($config) {
$def = $config->getCSSDefinition();
$this->info['background-color'] = $def->info['background-color'];
$this->info['background-image'] = $def->info['background-image'];
$this->info['background-repeat'] = $def->info['background-repeat'];
$this->info['background-attachment'] = $def->info['background-attachment'];
$this->info['background-position'] = $def->info['background-position'];
}
public function validate($string, $config, $context) {
// regular pre-processing
$string = $this->parseCDATA($string);
if ($string === '') return false;
// munge rgb() decl if necessary
$string = $this->mungeRgb($string);
// assumes URI doesn't have spaces in it
$bits = explode(' ', strtolower($string)); // bits to process
$caught = array();
$caught['color'] = false;
$caught['image'] = false;
$caught['repeat'] = false;
$caught['attachment'] = false;
$caught['position'] = false;
$i = 0; // number of catches
$none = false;
foreach ($bits as $bit) {
if ($bit === '') continue;
foreach ($caught as $key => $status) {
if ($key != 'position') {
if ($status !== false) continue;
$r = $this->info['background-' . $key]->validate($bit, $config, $context);
} else {
$r = $bit;
}
if ($r === false) continue;
if ($key == 'position') {
if ($caught[$key] === false) $caught[$key] = '';
$caught[$key] .= $r . ' ';
} else {
$caught[$key] = $r;
}
$i++;
break;
}
}
if (!$i) return false;
if ($caught['position'] !== false) {
$caught['position'] = $this->info['background-position']->
validate($caught['position'], $config, $context);
}
$ret = array();
foreach ($caught as $value) {
if ($value === false) continue;
$ret[] = $value;
}
if (empty($ret)) return false;
return implode(' ', $ret);
}
}
// vim: et sw=4 sts=4

@ -1,133 +0,0 @@
<?php
/* W3C says:
[ // adjective and number must be in correct order, even if
// you could switch them without introducing ambiguity.
// some browsers support that syntax
[
<percentage> | <length> | left | center | right
]
[
<percentage> | <length> | top | center | bottom
]?
] |
[ // this signifies that the vertical and horizontal adjectives
// can be arbitrarily ordered, however, there can only be two,
// one of each, or none at all
[
left | center | right
] ||
[
top | center | bottom
]
]
top, left = 0%
center, (none) = 50%
bottom, right = 100%
*/
/* QuirksMode says:
keyword + length/percentage must be ordered correctly, as per W3C
Internet Explorer and Opera, however, support arbitrary ordering. We
should fix it up.
Minor issue though, not strictly necessary.
*/
// control freaks may appreciate the ability to convert these to
// percentages or something, but it's not necessary
/**
* Validates the value of background-position.
*/
class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
{
protected $length;
protected $percentage;
public function __construct() {
$this->length = new HTMLPurifier_AttrDef_CSS_Length();
$this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage();
}
public function validate($string, $config, $context) {
$string = $this->parseCDATA($string);
$bits = explode(' ', $string);
$keywords = array();
$keywords['h'] = false; // left, right
$keywords['v'] = false; // top, bottom
$keywords['ch'] = false; // center (first word)
$keywords['cv'] = false; // center (second word)
$measures = array();
$i = 0;
$lookup = array(
'top' => 'v',
'bottom' => 'v',
'left' => 'h',
'right' => 'h',
'center' => 'c'
);
foreach ($bits as $bit) {
if ($bit === '') continue;
// test for keyword
$lbit = ctype_lower($bit) ? $bit : strtolower($bit);
if (isset($lookup[$lbit])) {
$status = $lookup[$lbit];
if ($status == 'c') {
if ($i == 0) {
$status = 'ch';
} else {
$status = 'cv';
}
}
$keywords[$status] = $lbit;
$i++;
}
// test for length
$r = $this->length->validate($bit, $config, $context);
if ($r !== false) {
$measures[] = $r;
$i++;
}
// test for percentage
$r = $this->percentage->validate($bit, $config, $context);
if ($r !== false) {
$measures[] = $r;
$i++;
}
}
if (!$i) return false; // no valid values were caught
$ret = array();
// first keyword
if ($keywords['h']) $ret[] = $keywords['h'];
elseif ($keywords['ch']) {
$ret[] = $keywords['ch'];
$keywords['cv'] = false; // prevent re-use: center = center center
}
elseif (count($measures)) $ret[] = array_shift($measures);
if ($keywords['v']) $ret[] = $keywords['v'];
elseif ($keywords['cv']) $ret[] = $keywords['cv'];
elseif (count($measures)) $ret[] = array_shift($measures);
if (empty($ret)) return false;
return implode(' ', $ret);
}
}
// vim: et sw=4 sts=4

@ -1,43 +0,0 @@
<?php
/**
* Validates the border property as defined by CSS.
*/
class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
{
/**
* Local copy of properties this property is shorthand for.
*/
protected $info = array();
public function __construct($config) {
$def = $config->getCSSDefinition();
$this->info['border-width'] = $def->info['border-width'];
$this->info['border-style'] = $def->info['border-style'];
$this->info['border-top-color'] = $def->info['border-top-color'];
}
public function validate($string, $config, $context) {
$string = $this->parseCDATA($string);
$string = $this->mungeRgb($string);
$bits = explode(' ', $string);
$done = array(); // segments we've finished
$ret = ''; // return value
foreach ($bits as $bit) {
foreach ($this->info as $propname => $validator) {
if (isset($done[$propname])) continue;
$r = $validator->validate($bit, $config, $context);
if ($r !== false) {
$ret .= $r . ' ';
$done[$propname] = true;
break;
}
}
}
return rtrim($ret);
}
}
// vim: et sw=4 sts=4

@ -1,78 +0,0 @@
<?php
/**
* Validates Color as defined by CSS.
*/
class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
{
public function validate($color, $config, $context) {
static $colors = null;
if ($colors === null) $colors = $config->get('Core.ColorKeywords');
$color = trim($color);
if ($color === '') return false;
$lower = strtolower($color);
if (isset($colors[$lower])) return $colors[$lower];
if (strpos($color, 'rgb(') !== false) {
// rgb literal handling
$length = strlen($color);
if (strpos($color, ')') !== $length - 1) return false;
$triad = substr($color, 4, $length - 4 - 1);
$parts = explode(',', $triad);
if (count($parts) !== 3) return false;
$type = false; // to ensure that they're all the same type
$new_parts = array();
foreach ($parts as $part) {
$part = trim($part);
if ($part === '') return false;
$length = strlen($part);
if ($part[$length - 1] === '%') {
// handle percents
if (!$type) {
$type = 'percentage';
} elseif ($type !== 'percentage') {
return false;
}
$num = (float) substr($part, 0, $length - 1);
if ($num < 0) $num = 0;
if ($num > 100) $num = 100;
$new_parts[] = "$num%";
} else {
// handle integers
if (!$type) {
$type = 'integer';
} elseif ($type !== 'integer') {
return false;
}
$num = (int) $part;
if ($num < 0) $num = 0;
if ($num > 255) $num = 255;
$new_parts[] = (string) $num;
}
}
$new_triad = implode(',', $new_parts);
$color = "rgb($new_triad)";
} else {
// hexadecimal handling
if ($color[0] === '#') {
$hex = substr($color, 1);
} else {
$hex = $color;
$color = '#' . $color;
}
$length = strlen($hex);
if ($length !== 3 && $length !== 6) return false;
if (!ctype_xdigit($hex)) return false;
}
return $color;
}
}
// vim: et sw=4 sts=4

@ -1,38 +0,0 @@
<?php
/**
* Allows multiple validators to attempt to validate attribute.
*
* Composite is just what it sounds like: a composite of many validators.
* This means that multiple HTMLPurifier_AttrDef objects will have a whack
* at the string. If one of them passes, that's what is returned. This is
* especially useful for CSS values, which often are a choice between
* an enumerated set of predefined values or a flexible data type.
*/
class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef
{
/**
* List of HTMLPurifier_AttrDef objects that may process strings
* @todo Make protected
*/
public $defs;
/**
* @param $defs List of HTMLPurifier_AttrDef objects
*/
public function __construct($defs) {
$this->defs = $defs;
}
public function validate($string, $config, $context) {
foreach ($this->defs as $i => $def) {
$result = $this->defs[$i]->validate($string, $config, $context);
if ($result !== false) return $result;
}
return false;
}
}
// vim: et sw=4 sts=4

@ -1,28 +0,0 @@
<?php
/**
* Decorator which enables CSS properties to be disabled for specific elements.
*/
class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef
{
public $def, $element;
/**
* @param $def Definition to wrap
* @param $element Element to deny
*/
public function __construct($def, $element) {
$this->def = $def;
$this->element = $element;
}
/**
* Checks if CurrentToken is set and equal to $this->element
*/
public function validate($string, $config, $context) {
$token = $context->get('CurrentToken', true);
if ($token && $token->name == $this->element) return false;
return $this->def->validate($string, $config, $context);
}
}
// vim: et sw=4 sts=4

@ -1,54 +0,0 @@
<?php
/**
* Microsoft's proprietary filter: CSS property
* @note Currently supports the alpha filter. In the future, this will
* probably need an extensible framework
*/
class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
{
protected $intValidator;
public function __construct() {
$this->intValidator = new HTMLPurifier_AttrDef_Integer();
}
public function validate($value, $config, $context) {
$value = $this->parseCDATA($value);
if ($value === 'none') return $value;
// if we looped this we could support multiple filters
$function_length = strcspn($value, '(');
$function = trim(substr($value, 0, $function_length));
if ($function !== 'alpha' &&
$function !== 'Alpha' &&
$function !== 'progid:DXImageTransform.Microsoft.Alpha'
) return false;
$cursor = $function_length + 1;
$parameters_length = strcspn($value, ')', $cursor);
$parameters = substr($value, $cursor, $parameters_length);
$params = explode(',', $parameters);
$ret_params = array();
$lookup = array();
foreach ($params as $param) {
list($key, $value) = explode('=', $param);
$key = trim($key);
$value = trim($value);
if (isset($lookup[$key])) continue;
if ($key !== 'opacity') continue;
$value = $this->intValidator->validate($value, $config, $context);
if ($value === false) continue;
$int = (int) $value;
if ($int > 100) $value = '100';
if ($int < 0) $value = '0';
$ret_params[] = "$key=$value";
$lookup[$key] = true;
}
$ret_parameters = implode(',', $ret_params);
$ret_function = "$function($ret_parameters)";
return $ret_function;
}
}
// vim: et sw=4 sts=4

@ -1,149 +0,0 @@
<?php
/**
* Validates shorthand CSS property font.
*/
class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
{
/**
* Local copy of component validators.
*
* @note If we moved specific CSS property definitions to their own
* classes instead of having them be assembled at run time by
* CSSDefinition, this wouldn't be necessary. We'd instantiate
* our own copies.
*/
protected $info = array();
public function __construct($config) {
$def = $config->getCSSDefinition();
$this->info['font-style'] = $def->info['font-style'];
$this->info['font-variant'] = $def->info['font-variant'];
$this->info['font-weight'] = $def->info['font-weight'];
$this->info['font-size'] = $def->info['font-size'];
$this->info['line-height'] = $def->info['line-height'];
$this->info['font-family'] = $def->info['font-family'];
}
public function validate($string, $config, $context) {
static $system_fonts = array(
'caption' => true,
'icon' => true,
'menu' => true,
'message-box' => true,
'small-caption' => true,
'status-bar' => true
);
// regular pre-processing
$string = $this->parseCDATA($string);
if ($string === '') return false;
// check if it's one of the keywords
$lowercase_string = strtolower($string);
if (isset($system_fonts[$lowercase_string])) {
return $lowercase_string;
}
$bits = explode(' ', $string); // bits to process
$stage = 0; // this indicates what we're looking for
$caught = array(); // which stage 0 properties have we caught?
$stage_1 = array('font-style', 'font-variant', 'font-weight');
$final = ''; // output
for ($i = 0, $size = count($bits); $i < $size; $i++) {
if ($bits[$i] === '') continue;
switch ($stage) {
// attempting to catch font-style, font-variant or font-weight
case 0:
foreach ($stage_1 as $validator_name) {
if (isset($caught[$validator_name])) continue;
$r = $this->info[$validator_name]->validate(
$bits[$i], $config, $context);
if ($r !== false) {
$final .= $r . ' ';
$caught[$validator_name] = true;
break;
}
}
// all three caught, continue on
if (count($caught) >= 3) $stage = 1;
if ($r !== false) break;
// attempting to catch font-size and perhaps line-height
case 1:
$found_slash = false;
if (strpos($bits[$i], '/') !== false) {
list($font_size, $line_height) =
explode('/', $bits[$i]);
if ($line_height === '') {
// ooh, there's a space after the slash!
$line_height = false;
$found_slash = true;
}
} else {
$font_size = $bits[$i];
$line_height = false;
}
$r = $this->info['font-size']->validate(
$font_size, $config, $context);
if ($r !== false) {
$final .= $r;
// attempt to catch line-height
if ($line_height === false) {
// we need to scroll forward
for ($j = $i + 1; $j < $size; $j++) {
if ($bits[$j] === '') continue;
if ($bits[$j] === '/') {
if ($found_slash) {
return false;
} else {
$found_slash = true;
continue;
}
}
$line_height = $bits[$j];
break;
}
} else {
// slash already found
$found_slash = true;
$j = $i;
}
if ($found_slash) {
$i = $j;
$r = $this->info['line-height']->validate(
$line_height, $config, $context);
if ($r !== false) {
$final .= '/' . $r;
}
}
$final .= ' ';
$stage = 2;
break;
}
return false;
// attempting to catch font-family
case 2:
$font_family =
implode(' ', array_slice($bits, $i, $size - $i));
$r = $this->info['font-family']->validate(
$font_family, $config, $context);
if ($r !== false) {
$final .= $r . ' ';
// processing completed successfully
return rtrim($final);
}
return false;
}
}
return false;
}
}
// vim: et sw=4 sts=4

@ -1,72 +0,0 @@
<?php
/**
* Validates a font family list according to CSS spec
* @todo whitelisting allowed fonts would be nice
*/
class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
{
public function validate($string, $config, $context) {
static $generic_names = array(
'serif' => true,
'sans-serif' => true,
'monospace' => true,
'fantasy' => true,
'cursive' => true
);
// assume that no font names contain commas in them
$fonts = explode(',', $string);
$final = '';
foreach($fonts as $font) {
$font = trim($font);
if ($font === '') continue;
// match a generic name
if (isset($generic_names[$font])) {
$final .= $font . ', ';
continue;
}
// match a quoted name
if ($font[0] === '"' || $font[0] === "'") {
$length = strlen($font);
if ($length <= 2) continue;
$quote = $font[0];
if ($font[$length - 1] !== $quote) continue;
$font = substr($font, 1, $length - 2);
}
$font = $this->expandCSSEscape($font);
// $font is a pure representation of the font name
if (ctype_alnum($font) && $font !== '') {
// very simple font, allow it in unharmed
$final .= $font . ', ';
continue;
}
// bugger out on whitespace. form feed (0C) really
// shouldn't show up regardless
$font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font);
// These ugly transforms don't pose a security
// risk (as \\ and \" might). We could try to be clever and
// use single-quote wrapping when there is a double quote
// present, but I have choosen not to implement that.
// (warning: this code relies on the selection of quotation
// mark below)
$font = str_replace('\\', '\\5C ', $font);
$font = str_replace('"', '\\22 ', $font);
// complicated font, requires quoting
$final .= "\"$font\", "; // note that this will later get turned into &quot;
}
$final = rtrim($final, ', ');
if ($final === '') return false;
return $final;
}
}
// vim: et sw=4 sts=4

@ -1,40 +0,0 @@
<?php
/**
* Decorator which enables !important to be used in CSS values.
*/
class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
{
public $def, $allow;
/**
* @param $def Definition to wrap
* @param $allow Whether or not to allow !important
*/
public function __construct($def, $allow = false) {
$this->def = $def;
$this->allow = $allow;
}
/**
* Intercepts and removes !important if necessary
*/
public function validate($string, $config, $context) {
// test for ! and important tokens
$string = trim($string);
$is_important = false;
// :TODO: optimization: test directly for !important and ! important
if (strlen($string) >= 9 && substr($string, -9) === 'important') {
$temp = rtrim(substr($string, 0, -9));
// use a temp, because we might want to restore important
if (strlen($temp) >= 1 && substr($temp, -1) === '!') {
$string = rtrim(substr($temp, 0, -1));
$is_important = true;
}
}
$string = $this->def->validate($string, $config, $context);
if ($this->allow && $is_important) $string .= ' !important';
return $string;
}
}
// vim: et sw=4 sts=4

@ -1,47 +0,0 @@
<?php
/**
* Represents a Length as defined by CSS.
*/
class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef
{
protected $min, $max;
/**
* @param HTMLPurifier_Length $max Minimum length, or null for no bound. String is also acceptable.
* @param HTMLPurifier_Length $max Maximum length, or null for no bound. String is also acceptable.
*/
public function __construct($min = null, $max = null) {
$this->min = $min !== null ? HTMLPurifier_Length::make($min) : null;
$this->max = $max !== null ? HTMLPurifier_Length::make($max) : null;
}
public function validate($string, $config, $context) {
$string = $this->parseCDATA($string);
// Optimizations
if ($string === '') return false;
if ($string === '0') return '0';
if (strlen($string) === 1) return false;
$length = HTMLPurifier_Length::make($string);
if (!$length->isValid()) return false;
if ($this->min) {
$c = $length->compareTo($this->min);
if ($c === false) return false;
if ($c < 0) return false;
}
if ($this->max) {
$c = $length->compareTo($this->max);
if ($c === false) return false;
if ($c > 0) return false;
}
return $length->toString();
}
}
// vim: et sw=4 sts=4

@ -1,78 +0,0 @@
<?php
/**
* Validates shorthand CSS property list-style.
* @warning Does not support url tokens that have internal spaces.
*/
class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
{
/**
* Local copy of component validators.
* @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl.
*/
protected $info;
public function __construct($config) {
$def = $config->getCSSDefinition();
$this->info['list-style-type'] = $def->info['list-style-type'];
$this->info['list-style-position'] = $def->info['list-style-position'];
$this->info['list-style-image'] = $def->info['list-style-image'];
}
public function validate($string, $config, $context) {
// regular pre-processing
$string = $this->parseCDATA($string);
if ($string === '') return false;
// assumes URI doesn't have spaces in it
$bits = explode(' ', strtolower($string)); // bits to process
$caught = array();
$caught['type'] = false;
$caught['position'] = false;
$caught['image'] = false;
$i = 0; // number of catches
$none = false;
foreach ($bits as $bit) {
if ($i >= 3) return; // optimization bit
if ($bit === '') continue;
foreach ($caught as $key => $status) {
if ($status !== false) continue;
$r = $this->info['list-style-' . $key]->validate($bit, $config, $context);
if ($r === false) continue;
if ($r === 'none') {
if ($none) continue;
else $none = true;
if ($key == 'image') continue;
}
$caught[$key] = $r;
$i++;
break;
}
}
if (!$i) return false;
$ret = array();
// construct type
if ($caught['type']) $ret[] = $caught['type'];
// construct image
if ($caught['image']) $ret[] = $caught['image'];
// construct position
if ($caught['position']) $ret[] = $caught['position'];
if (empty($ret)) return false;
return implode(' ', $ret);
}
}
// vim: et sw=4 sts=4

@ -1,58 +0,0 @@
<?php
/**
* Framework class for strings that involve multiple values.
*
* Certain CSS properties such as border-width and margin allow multiple
* lengths to be specified. This class can take a vanilla border-width
* definition and multiply it, usually into a max of four.
*
* @note Even though the CSS specification isn't clear about it, inherit
* can only be used alone: it will never manifest as part of a multi
* shorthand declaration. Thus, this class does not allow inherit.
*/
class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
{
/**
* Instance of component definition to defer validation to.
* @todo Make protected
*/
public $single;
/**
* Max number of values allowed.
* @todo Make protected
*/
public $max;
/**
* @param $single HTMLPurifier_AttrDef to multiply
* @param $max Max number of values allowed (usually four)
*/
public function __construct($single, $max = 4) {
$this->single = $single;
$this->max = $max;
}
public function validate($string, $config, $context) {
$string = $this->parseCDATA($string);
if ($string === '') return false;
$parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n
$length = count($parts);
$final = '';
for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) {
if (ctype_space($parts[$i])) continue;
$result = $this->single->validate($parts[$i], $config, $context);
if ($result !== false) {
$final .= $result . ' ';
$num++;
}
}
if ($final === '') return false;
return rtrim($final);
}
}
// vim: et sw=4 sts=4

@ -1,69 +0,0 @@
<?php
/**
* Validates a number as defined by the CSS spec.
*/
class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
{
/**
* Bool indicating whether or not only positive values allowed.
*/
protected $non_negative = false;
/**
* @param $non_negative Bool indicating whether negatives are forbidden
*/
public function __construct($non_negative = false) {
$this->non_negative = $non_negative;
}
/**
* @warning Some contexts do not pass $config, $context. These
* variables should not be used without checking HTMLPurifier_Length
*/
public function validate($number, $config, $context) {
$number = $this->parseCDATA($number);
if ($number === '') return false;
if ($number === '0') return '0';
$sign = '';
switch ($number[0]) {
case '-':
if ($this->non_negative) return false;
$sign = '-';
case '+':
$number = substr($number, 1);
}
if (ctype_digit($number)) {
$number = ltrim($number, '0');
return $number ? $sign . $number : '0';
}
// Period is the only non-numeric character allowed
if (strpos($number, '.') === false) return false;
list($left, $right) = explode('.', $number, 2);
if ($left === '' && $right === '') return false;
if ($left !== '' && !ctype_digit($left)) return false;
$left = ltrim($left, '0');
$right = rtrim($right, '0');
if ($right === '') {
return $left ? $sign . $left : '0';
} elseif (!ctype_digit($right)) {
return false;
}
return $sign . $left . '.' . $right;
}
}
// vim: et sw=4 sts=4

@ -1,40 +0,0 @@
<?php
/**
* Validates a Percentage as defined by the CSS spec.
*/
class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef
{
/**
* Instance of HTMLPurifier_AttrDef_CSS_Number to defer number validation
*/
protected $number_def;
/**
* @param Bool indicating whether to forbid negative values
*/
public function __construct($non_negative = false) {
$this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative);
}
public function validate($string, $config, $context) {
$string = $this->parseCDATA($string);
if ($string === '') return false;
$length = strlen($string);
if ($length === 1) return false;
if ($string[$length - 1] !== '%') return false;
$number = substr($string, 0, $length - 1);
$number = $this->number_def->validate($number, $config, $context);
if ($number === false) return false;
return "$number%";
}
}
// vim: et sw=4 sts=4

@ -1,38 +0,0 @@
<?php
/**
* Validates the value for the CSS property text-decoration
* @note This class could be generalized into a version that acts sort of
* like Enum except you can compound the allowed values.
*/
class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
{
public function validate($string, $config, $context) {
static $allowed_values = array(
'line-through' => true,
'overline' => true,
'underline' => true,
);
$string = strtolower($this->parseCDATA($string));
if ($string === 'none') return $string;
$parts = explode(' ', $string);
$final = '';
foreach ($parts as $part) {
if (isset($allowed_values[$part])) {
$final .= $part . ' ';
}
}
$final = rtrim($final);
if ($final === '') return false;
return $final;
}
}
// vim: et sw=4 sts=4

@ -1,52 +0,0 @@
<?php
/**
* Validates a URI in CSS syntax, which uses url('http://example.com')
* @note While theoretically speaking a URI in a CSS document could
* be non-embedded, as of CSS2 there is no such usage so we're
* generalizing it. This may need to be changed in the future.
* @warning Since HTMLPurifier_AttrDef_CSS blindly uses semicolons as
* the separator, you cannot put a literal semicolon in
* in the URI. Try percent encoding it, in that case.
*/
class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
{
public function __construct() {
parent::__construct(true); // always embedded
}
public function validate($uri_string, $config, $context) {
// parse the URI out of the string and then pass it onto
// the parent object
$uri_string = $this->parseCDATA($uri_string);
if (strpos($uri_string, 'url(') !== 0) return false;
$uri_string = substr($uri_string, 4);
$new_length = strlen($uri_string) - 1;
if ($uri_string[$new_length] != ')') return false;
$uri = trim(substr($uri_string, 0, $new_length));
if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) {
$quote = $uri[0];
$new_length = strlen($uri) - 1;
if ($uri[$new_length] !== $quote) return false;
$uri = substr($uri, 1, $new_length - 1);
}
$uri = $this->expandCSSEscape($uri);
$result = parent::validate($uri, $config, $context);
if ($result === false) return false;
// extra sanity check; should have been done by URI
$result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result);
return "url(\"$result\")";
}
}
// vim: et sw=4 sts=4

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,65 +0,0 @@
<?php
// Enum = Enumerated
/**
* Validates a keyword against a list of valid values.
* @warning The case-insensitive compare of this function uses PHP's
* built-in strtolower and ctype_lower functions, which may
* cause problems with international comparisons
*/
class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
{
/**
* Lookup table of valid values.
* @todo Make protected
*/
public $valid_values = array();
/**
* Bool indicating whether or not enumeration is case sensitive.
* @note In general this is always case insensitive.
*/
protected $case_sensitive = false; // values according to W3C spec
/**
* @param $valid_values List of valid values
* @param $case_sensitive Bool indicating whether or not case sensitive
*/
public function __construct(
$valid_values = array(), $case_sensitive = false
) {
$this->valid_values = array_flip($valid_values);
$this->case_sensitive = $case_sensitive;
}
public function validate($string, $config, $context) {
$string = trim($string);
if (!$this->case_sensitive) {
// we may want to do full case-insensitive libraries
$string = ctype_lower($string) ? $string : strtolower($string);
}
$result = isset($this->valid_values[$string]);
return $result ? $string : false;
}
/**
* @param $string In form of comma-delimited list of case-insensitive
* valid values. Example: "foo,bar,baz". Prepend "s:" to make
* case sensitive
*/
public function make($string) {
if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') {
$string = substr($string, 2);
$sensitive = true;
} else {
$sensitive = false;
}
$values = explode(',', $string);
return new HTMLPurifier_AttrDef_Enum($values, $sensitive);
}
}
// vim: et sw=4 sts=4

@ -1,28 +0,0 @@
<?php
/**
* Validates a boolean attribute
*/
class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef
{
protected $name;
public $minimized = true;
public function __construct($name = false) {$this->name = $name;}
public function validate($string, $config, $context) {
if (empty($string)) return false;
return $this->name;
}
/**
* @param $string Name of attribute
*/
public function make($string) {
return new HTMLPurifier_AttrDef_HTML_Bool($string);
}
}
// vim: et sw=4 sts=4

@ -1,34 +0,0 @@
<?php
/**
* Implements special behavior for class attribute (normally NMTOKENS)
*/
class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens
{
protected function split($string, $config, $context) {
// really, this twiddle should be lazy loaded
$name = $config->getDefinition('HTML')->doctype->name;
if ($name == "XHTML 1.1" || $name == "XHTML 2.0") {
return parent::split($string, $config, $context);
} else {
return preg_split('/\s+/', $string);
}
}
protected function filter($tokens, $config, $context) {
$allowed = $config->get('Attr.AllowedClasses');
$forbidden = $config->get('Attr.ForbiddenClasses');
$ret = array();
foreach ($tokens as $token) {
if (
($allowed === null || isset($allowed[$token])) &&
!isset($forbidden[$token]) &&
// We need this O(n) check because of PHP's array
// implementation that casts -0 to 0.
!in_array($token, $ret, true)
) {
$ret[] = $token;
}
}
return $ret;
}
}

@ -1,32 +0,0 @@
<?php
/**
* Validates a color according to the HTML spec.
*/
class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef
{
public function validate($string, $config, $context) {
static $colors = null;
if ($colors === null) $colors = $config->get('Core.ColorKeywords');
$string = trim($string);
if (empty($string)) return false;
if (isset($colors[$string])) return $colors[$string];
if ($string[0] === '#') $hex = substr($string, 1);
else $hex = $string;
$length = strlen($hex);
if ($length !== 3 && $length !== 6) return false;
if (!ctype_xdigit($hex)) return false;
if ($length === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
return "#$hex";
}
}
// vim: et sw=4 sts=4

@ -1,21 +0,0 @@
<?php
/**
* Special-case enum attribute definition that lazy loads allowed frame targets
*/
class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum
{
public $valid_values = false; // uninitialized value
protected $case_sensitive = false;
public function __construct() {}
public function validate($string, $config, $context) {
if ($this->valid_values === false) $this->valid_values = $config->get('Attr.AllowedFrameTargets');
return parent::validate($string, $config, $context);
}
}
// vim: et sw=4 sts=4

@ -1,70 +0,0 @@
<?php
/**
* Validates the HTML attribute ID.
* @warning Even though this is the id processor, it
* will ignore the directive Attr:IDBlacklist, since it will only
* go according to the ID accumulator. Since the accumulator is
* automatically generated, it will have already absorbed the
* blacklist. If you're hacking around, make sure you use load()!
*/
class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
{
// ref functionality disabled, since we also have to verify
// whether or not the ID it refers to exists
public function validate($id, $config, $context) {
if (!$config->get('Attr.EnableID')) return false;
$id = trim($id); // trim it first
if ($id === '') return false;
$prefix = $config->get('Attr.IDPrefix');
if ($prefix !== '') {
$prefix .= $config->get('Attr.IDPrefixLocal');
// prevent re-appending the prefix
if (strpos($id, $prefix) !== 0) $id = $prefix . $id;
} elseif ($config->get('Attr.IDPrefixLocal') !== '') {
trigger_error('%Attr.IDPrefixLocal cannot be used unless '.
'%Attr.IDPrefix is set', E_USER_WARNING);
}
//if (!$this->ref) {
$id_accumulator =& $context->get('IDAccumulator');
if (isset($id_accumulator->ids[$id])) return false;
//}
// we purposely avoid using regex, hopefully this is faster
if (ctype_alpha($id)) {
$result = true;
} else {
if (!ctype_alpha(@$id[0])) return false;
$trim = trim( // primitive style of regexps, I suppose
$id,
'A..Za..z0..9:-._'
);
$result = ($trim === '');
}
$regexp = $config->get('Attr.IDBlacklistRegexp');
if ($regexp && preg_match($regexp, $id)) {
return false;
}
if (/*!$this->ref && */$result) $id_accumulator->add($id);
// if no change was made to the ID, return the result
// else, return the new id if stripping whitespace made it
// valid, or return false.
return $result ? $id : false;
}
}
// vim: et sw=4 sts=4

@ -1,41 +0,0 @@
<?php
/**
* Validates the HTML type length (not to be confused with CSS's length).
*
* This accepts integer pixels or percentages as lengths for certain
* HTML attributes.
*/
class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels
{
public function validate($string, $config, $context) {
$string = trim($string);
if ($string === '') return false;
$parent_result = parent::validate($string, $config, $context);
if ($parent_result !== false) return $parent_result;
$length = strlen($string);
$last_char = $string[$length - 1];
if ($last_char !== '%') return false;
$points = substr($string, 0, $length - 1);
if (!is_numeric($points)) return false;
$points = (int) $points;
if ($points < 0) return '0%';
if ($points > 100) return '100%';
return ((string) $points) . '%';
}
}
// vim: et sw=4 sts=4

@ -1,53 +0,0 @@
<?php
/**
* Validates a rel/rev link attribute against a directive of allowed values
* @note We cannot use Enum because link types allow multiple
* values.
* @note Assumes link types are ASCII text
*/
class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
{
/** Name config attribute to pull. */
protected $name;
public function __construct($name) {
$configLookup = array(
'rel' => 'AllowedRel',
'rev' => 'AllowedRev'
);
if (!isset($configLookup[$name])) {
trigger_error('Unrecognized attribute name for link '.
'relationship.', E_USER_ERROR);
return;
}
$this->name = $configLookup[$name];
}
public function validate($string, $config, $context) {
$allowed = $config->get('Attr.' . $this->name);
if (empty($allowed)) return false;
$string = $this->parseCDATA($string);
$parts = explode(' ', $string);
// lookup to prevent duplicates
$ret_lookup = array();
foreach ($parts as $part) {
$part = strtolower(trim($part));
if (!isset($allowed[$part])) continue;
$ret_lookup[$part] = true;
}
if (empty($ret_lookup)) return false;
$string = implode(' ', array_keys($ret_lookup));
return $string;
}
}
// vim: et sw=4 sts=4

@ -1,41 +0,0 @@
<?php
/**
* Validates a MultiLength as defined by the HTML spec.
*
* A multilength is either a integer (pixel count), a percentage, or
* a relative number.
*/
class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Length
{
public function validate($string, $config, $context) {
$string = trim($string);
if ($string === '') return false;
$parent_result = parent::validate($string, $config, $context);
if ($parent_result !== false) return $parent_result;
$length = strlen($string);
$last_char = $string[$length - 1];
if ($last_char !== '*') return false;
$int = substr($string, 0, $length - 1);
if ($int == '') return '*';
if (!is_numeric($int)) return false;
$int = (int) $int;
if ($int < 0) return false;
if ($int == 0) return '0';
if ($int == 1) return '*';
return ((string) $int) . '*';
}
}
// vim: et sw=4 sts=4

@ -1,52 +0,0 @@
<?php
/**
* Validates contents based on NMTOKENS attribute type.
*/
class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
{
public function validate($string, $config, $context) {
$string = trim($string);
// early abort: '' and '0' (strings that convert to false) are invalid
if (!$string) return false;
$tokens = $this->split($string, $config, $context);
$tokens = $this->filter($tokens, $config, $context);
if (empty($tokens)) return false;
return implode(' ', $tokens);
}
/**
* Splits a space separated list of tokens into its constituent parts.
*/
protected function split($string, $config, $context) {
// OPTIMIZABLE!
// do the preg_match, capture all subpatterns for reformulation
// we don't support U+00A1 and up codepoints or
// escaping because I don't know how to do that with regexps
// and plus it would complicate optimization efforts (you never
// see that anyway).
$pattern = '/(?:(?<=\s)|\A)'. // look behind for space or string start
'((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)'.
'(?:(?=\s)|\z)/'; // look ahead for space or string end
preg_match_all($pattern, $string, $matches);
return $matches[1];
}
/**
* Template method for removing certain tokens based on arbitrary criteria.
* @note If we wanted to be really functional, we'd do an array_filter
* with a callback. But... we're not.
*/
protected function filter($tokens, $config, $context) {
return $tokens;
}
}
// vim: et sw=4 sts=4

@ -1,48 +0,0 @@
<?php
/**
* Validates an integer representation of pixels according to the HTML spec.
*/
class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef
{
protected $max;
public function __construct($max = null) {
$this->max = $max;
}
public function validate($string, $config, $context) {
$string = trim($string);
if ($string === '0') return $string;
if ($string === '') return false;
$length = strlen($string);
if (substr($string, $length - 2) == 'px') {
$string = substr($string, 0, $length - 2);
}
if (!is_numeric($string)) return false;
$int = (int) $string;
if ($int < 0) return '0';
// upper-bound value, extremely high values can
// crash operating systems, see <http://ha.ckers.org/imagecrash.html>
// WARNING, above link WILL crash you if you're using Windows
if ($this->max !== null && $int > $this->max) return (string) $this->max;
return (string) $int;
}
public function make($string) {
if ($string === '') $max = null;
else $max = (int) $string;
$class = get_class($this);
return new $class($max);
}
}
// vim: et sw=4 sts=4

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,73 +0,0 @@
<?php
/**
* Validates an integer.
* @note While this class was modeled off the CSS definition, no currently
* allowed CSS uses this type. The properties that do are: widows,
* orphans, z-index, counter-increment, counter-reset. Some of the
* HTML attributes, however, find use for a non-negative version of this.
*/
class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef
{
/**
* Bool indicating whether or not negative values are allowed
*/
protected $negative = true;
/**
* Bool indicating whether or not zero is allowed
*/
protected $zero = true;
/**
* Bool indicating whether or not positive values are allowed
*/
protected $positive = true;
/**
* @param $negative Bool indicating whether or not negative values are allowed
* @param $zero Bool indicating whether or not zero is allowed
* @param $positive Bool indicating whether or not positive values are allowed
*/
public function __construct(
$negative = true, $zero = true, $positive = true
) {
$this->negative = $negative;
$this->zero = $zero;
$this->positive = $positive;
}
public function validate($integer, $config, $context) {
$integer = $this->parseCDATA($integer);
if ($integer === '') return false;
// we could possibly simply typecast it to integer, but there are
// certain fringe cases that must not return an integer.
// clip leading sign
if ( $this->negative && $integer[0] === '-' ) {
$digits = substr($integer, 1);
if ($digits === '0') $integer = '0'; // rm minus sign for zero
} elseif( $this->positive && $integer[0] === '+' ) {
$digits = $integer = substr($integer, 1); // rm unnecessary plus
} else {
$digits = $integer;
}
// test if it's numeric
if (!ctype_digit($digits)) return false;
// perform scope tests
if (!$this->zero && $integer == 0) return false;
if (!$this->positive && $integer > 0) return false;
if (!$this->negative && $integer < 0) return false;
return $integer;
}
}
// vim: et sw=4 sts=4

@ -1,73 +0,0 @@
<?php
/**
* Validates the HTML attribute lang, effectively a language code.
* @note Built according to RFC 3066, which obsoleted RFC 1766
*/
class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
{
public function validate($string, $config, $context) {
$string = trim($string);
if (!$string) return false;
$subtags = explode('-', $string);
$num_subtags = count($subtags);
if ($num_subtags == 0) return false; // sanity check
// process primary subtag : $subtags[0]
$length = strlen($subtags[0]);
switch ($length) {
case 0:
return false;
case 1:
if (! ($subtags[0] == 'x' || $subtags[0] == 'i') ) {
return false;
}
break;
case 2:
case 3:
if (! ctype_alpha($subtags[0]) ) {
return false;
} elseif (! ctype_lower($subtags[0]) ) {
$subtags[0] = strtolower($subtags[0]);
}
break;
default:
return false;
}
$new_string = $subtags[0];
if ($num_subtags == 1) return $new_string;
// process second subtag : $subtags[1]
$length = strlen($subtags[1]);
if ($length == 0 || ($length == 1 && $subtags[1] != 'x') || $length > 8 || !ctype_alnum($subtags[1])) {
return $new_string;
}
if (!ctype_lower($subtags[1])) $subtags[1] = strtolower($subtags[1]);
$new_string .= '-' . $subtags[1];
if ($num_subtags == 2) return $new_string;
// process all other subtags, index 2 and up
for ($i = 2; $i < $num_subtags; $i++) {
$length = strlen($subtags[$i]);
if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) {
return $new_string;
}
if (!ctype_lower($subtags[$i])) {
$subtags[$i] = strtolower($subtags[$i]);
}
$new_string .= '-' . $subtags[$i];
}
return $new_string;
}
}
// vim: et sw=4 sts=4

@ -1,34 +0,0 @@
<?php
/**
* Decorator that, depending on a token, switches between two definitions.
*/
class HTMLPurifier_AttrDef_Switch
{
protected $tag;
protected $withTag, $withoutTag;
/**
* @param string $tag Tag name to switch upon
* @param HTMLPurifier_AttrDef $with_tag Call if token matches tag
* @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token
*/
public function __construct($tag, $with_tag, $without_tag) {
$this->tag = $tag;
$this->withTag = $with_tag;
$this->withoutTag = $without_tag;
}
public function validate($string, $config, $context) {
$token = $context->get('CurrentToken', true);
if (!$token || $token->name !== $this->tag) {
return $this->withoutTag->validate($string, $config, $context);
} else {
return $this->withTag->validate($string, $config, $context);
}
}
}
// vim: et sw=4 sts=4

@ -1,15 +0,0 @@
<?php
/**
* Validates arbitrary text according to the HTML spec.
*/
class HTMLPurifier_AttrDef_Text extends HTMLPurifier_AttrDef
{
public function validate($string, $config, $context) {
return $this->parseCDATA($string);
}
}
// vim: et sw=4 sts=4

@ -1,77 +0,0 @@
<?php
/**
* Validates a URI as defined by RFC 3986.
* @note Scheme-specific mechanics deferred to HTMLPurifier_URIScheme
*/
class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
{
protected $parser;
protected $embedsResource;
/**
* @param $embeds_resource_resource Does the URI here result in an extra HTTP request?
*/
public function __construct($embeds_resource = false) {
$this->parser = new HTMLPurifier_URIParser();
$this->embedsResource = (bool) $embeds_resource;
}
public function make($string) {
$embeds = (bool) $string;
return new HTMLPurifier_AttrDef_URI($embeds);
}
public function validate($uri, $config, $context) {
if ($config->get('URI.Disable')) return false;
$uri = $this->parseCDATA($uri);
// parse the URI
$uri = $this->parser->parse($uri);
if ($uri === false) return false;
// add embedded flag to context for validators
$context->register('EmbeddedURI', $this->embedsResource);
$ok = false;
do {
// generic validation
$result = $uri->validate($config, $context);
if (!$result) break;
// chained filtering
$uri_def = $config->getDefinition('URI');
$result = $uri_def->filter($uri, $config, $context);
if (!$result) break;
// scheme-specific validation
$scheme_obj = $uri->getSchemeObj($config, $context);
if (!$scheme_obj) break;
if ($this->embedsResource && !$scheme_obj->browsable) break;
$result = $scheme_obj->validate($uri, $config, $context);
if (!$result) break;
// Post chained filtering
$result = $uri_def->postFilter($uri, $config, $context);
if (!$result) break;
// survived gauntlet
$ok = true;
} while (false);
$context->destroy('EmbeddedURI');
if (!$ok) return false;
// back to string
return $uri->toString();
}
}
// vim: et sw=4 sts=4

@ -1,17 +0,0 @@
<?php
abstract class HTMLPurifier_AttrDef_URI_Email extends HTMLPurifier_AttrDef
{
/**
* Unpacks a mailbox into its display-name and address
*/
function unpack($string) {
// needs to be implemented
}
}
// sub-implementations
// vim: et sw=4 sts=4

@ -1,21 +0,0 @@
<?php
/**
* Primitive email validation class based on the regexp found at
* http://www.regular-expressions.info/email.html
*/
class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_URI_Email
{
public function validate($string, $config, $context) {
// no support for named mailboxes i.e. "Bob <bob@example.com>"
// that needs more percent encoding to be done
if ($string == '') return false;
$string = trim($string);
$result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string);
return $result ? $string : false;
}
}
// vim: et sw=4 sts=4

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,68 +0,0 @@
<?php
/**
* Validates a host according to the IPv4, IPv6 and DNS (future) specifications.
*/
class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
{
/**
* Instance of HTMLPurifier_AttrDef_URI_IPv4 sub-validator
*/
protected $ipv4;
/**
* Instance of HTMLPurifier_AttrDef_URI_IPv6 sub-validator
*/
protected $ipv6;
public function __construct() {
$this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4();
$this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6();
}
public function validate($string, $config, $context) {
$length = strlen($string);
// empty hostname is OK; it's usually semantically equivalent:
// the default host as defined by a URI scheme is used:
//
// If the URI scheme defines a default for host, then that
// default applies when the host subcomponent is undefined
// or when the registered name is empty (zero length).
if ($string === '') return '';
if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') {
//IPv6
$ip = substr($string, 1, $length - 2);
$valid = $this->ipv6->validate($ip, $config, $context);
if ($valid === false) return false;
return '['. $valid . ']';
}
// need to do checks on unusual encodings too
$ipv4 = $this->ipv4->validate($string, $config, $context);
if ($ipv4 !== false) return $ipv4;
// A regular domain name.
// This breaks I18N domain names, but we don't have proper IRI support,
// so force users to insert Punycode. If there's complaining we'll
// try to fix things into an international friendly form.
// The productions describing this are:
$a = '[a-z]'; // alpha
$an = '[a-z0-9]'; // alphanum
$and = '[a-z0-9-]'; // alphanum | "-"
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
$domainlabel = "$an($and*$an)?";
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum
$toplabel = "$a($and*$an)?";
// hostname = *( domainlabel "." ) toplabel [ "." ]
$match = preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string);
if (!$match) return false;
return $string;
}
}
// vim: et sw=4 sts=4

@ -1,39 +0,0 @@
<?php
/**
* Validates an IPv4 address
* @author Feyd @ forums.devnetwork.net (public domain)
*/
class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef
{
/**
* IPv4 regex, protected so that IPv6 can reuse it
*/
protected $ip4;
public function validate($aIP, $config, $context) {
if (!$this->ip4) $this->_loadRegex();
if (preg_match('#^' . $this->ip4 . '$#s', $aIP))
{
return $aIP;
}
return false;
}
/**
* Lazy load function to prevent regex from being stuffed in
* cache.
*/
protected function _loadRegex() {
$oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255
$this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})";
}
}
// vim: et sw=4 sts=4

@ -1,99 +0,0 @@
<?php
/**
* Validates an IPv6 address.
* @author Feyd @ forums.devnetwork.net (public domain)
* @note This function requires brackets to have been removed from address
* in URI.
*/
class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4
{
public function validate($aIP, $config, $context) {
if (!$this->ip4) $this->_loadRegex();
$original = $aIP;
$hex = '[0-9a-fA-F]';
$blk = '(?:' . $hex . '{1,4})';
$pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128
// prefix check
if (strpos($aIP, '/') !== false)
{
if (preg_match('#' . $pre . '$#s', $aIP, $find))
{
$aIP = substr($aIP, 0, 0-strlen($find[0]));
unset($find);
}
else
{
return false;
}
}
// IPv4-compatiblity check
if (preg_match('#(?<=:'.')' . $this->ip4 . '$#s', $aIP, $find))
{
$aIP = substr($aIP, 0, 0-strlen($find[0]));
$ip = explode('.', $find[0]);
$ip = array_map('dechex', $ip);
$aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3];
unset($find, $ip);
}
// compression check
$aIP = explode('::', $aIP);
$c = count($aIP);
if ($c > 2)
{
return false;
}
elseif ($c == 2)
{
list($first, $second) = $aIP;
$first = explode(':', $first);
$second = explode(':', $second);
if (count($first) + count($second) > 8)
{
return false;
}
while(count($first) < 8)
{
array_push($first, '0');
}
array_splice($first, 8 - count($second), 8, $second);
$aIP = $first;
unset($first,$second);
}
else
{
$aIP = explode(':', $aIP[0]);
}
$c = count($aIP);
if ($c != 8)
{
return false;
}
// All the pieces should be 16-bit hex strings. Are they?
foreach ($aIP as $piece)
{
if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece)))
{
return false;
}
}
return $original;
}
}
// vim: et sw=4 sts=4

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -1,56 +0,0 @@
<?php
/**
* Processes an entire attribute array for corrections needing multiple values.
*
* Occasionally, a certain attribute will need to be removed and popped onto
* another value. Instead of creating a complex return syntax for
* HTMLPurifier_AttrDef, we just pass the whole attribute array to a
* specialized object and have that do the special work. That is the
* family of HTMLPurifier_AttrTransform.
*
* An attribute transformation can be assigned to run before or after
* HTMLPurifier_AttrDef validation. See HTMLPurifier_HTMLDefinition for
* more details.
*/
abstract class HTMLPurifier_AttrTransform
{
/**
* Abstract: makes changes to the attributes dependent on multiple values.
*
* @param $attr Assoc array of attributes, usually from
* HTMLPurifier_Token_Tag::$attr
* @param $config Mandatory HTMLPurifier_Config object.
* @param $context Mandatory HTMLPurifier_Context object
* @returns Processed attribute array.
*/
abstract public function transform($attr, $config, $context);
/**
* Prepends CSS properties to the style attribute, creating the
* attribute if it doesn't exist.
* @param $attr Attribute array to process (passed by reference)
* @param $css CSS to prepend
*/
public function prependCSS(&$attr, $css) {
$attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = $css . $attr['style'];
}
/**
* Retrieves and removes an attribute
* @param $attr Attribute array to process (passed by reference)
* @param $key Key of attribute to confiscate
*/
public function confiscateAttr(&$attr, $key) {
if (!isset($attr[$key])) return null;
$value = $attr[$key];
unset($attr[$key]);
return $value;
}
}
// vim: et sw=4 sts=4

@ -1,23 +0,0 @@
<?php
/**
* Pre-transform that changes proprietary background attribute to CSS.
*/
class HTMLPurifier_AttrTransform_Background extends HTMLPurifier_AttrTransform {
public function transform($attr, $config, $context) {
if (!isset($attr['background'])) return $attr;
$background = $this->confiscateAttr($attr, 'background');
// some validation should happen here
$this->prependCSS($attr, "background-image:url($background);");
return $attr;
}
}
// vim: et sw=4 sts=4

@ -1,19 +0,0 @@
<?php
// this MUST be placed in post, as it assumes that any value in dir is valid
/**
* Post-trasnform that ensures that bdo tags have the dir attribute set.
*/
class HTMLPurifier_AttrTransform_BdoDir extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) {
if (isset($attr['dir'])) return $attr;
$attr['dir'] = $config->get('Attr.DefaultTextDir');
return $attr;
}
}
// vim: et sw=4 sts=4

@ -1,23 +0,0 @@
<?php
/**
* Pre-transform that changes deprecated bgcolor attribute to CSS.
*/
class HTMLPurifier_AttrTransform_BgColor extends HTMLPurifier_AttrTransform {
public function transform($attr, $config, $context) {
if (!isset($attr['bgcolor'])) return $attr;
$bgcolor = $this->confiscateAttr($attr, 'bgcolor');
// some validation should happen here
$this->prependCSS($attr, "background-color:$bgcolor;");
return $attr;
}
}
// vim: et sw=4 sts=4

@ -1,36 +0,0 @@
<?php
/**
* Pre-transform that changes converts a boolean attribute to fixed CSS
*/
class HTMLPurifier_AttrTransform_BoolToCSS extends HTMLPurifier_AttrTransform {
/**
* Name of boolean attribute that is trigger
*/
protected $attr;
/**
* CSS declarations to add to style, needs trailing semicolon
*/
protected $css;
/**
* @param $attr string attribute name to convert from
* @param $css string CSS declarations to add to style (needs semicolon)
*/
public function __construct($attr, $css) {
$this->attr = $attr;
$this->css = $css;
}
public function transform($attr, $config, $context) {
if (!isset($attr[$this->attr])) return $attr;
unset($attr[$this->attr]);
$this->prependCSS($attr, $this->css);
return $attr;
}
}
// vim: et sw=4 sts=4

@ -1,18 +0,0 @@
<?php
/**
* Pre-transform that changes deprecated border attribute to CSS.
*/
class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform {
public function transform($attr, $config, $context) {
if (!isset($attr['border'])) return $attr;
$border_width = $this->confiscateAttr($attr, 'border');
// some validation should happen here
$this->prependCSS($attr, "border:{$border_width}px solid;");
return $attr;
}
}
// vim: et sw=4 sts=4

@ -1,58 +0,0 @@
<?php
/**
* Generic pre-transform that converts an attribute with a fixed number of
* values (enumerated) to CSS.
*/
class HTMLPurifier_AttrTransform_EnumToCSS extends HTMLPurifier_AttrTransform {
/**
* Name of attribute to transform from
*/
protected $attr;
/**
* Lookup array of attribute values to CSS
*/
protected $enumToCSS = array();
/**
* Case sensitivity of the matching
* @warning Currently can only be guaranteed to work with ASCII
* values.
*/
protected $caseSensitive = false;
/**
* @param $attr String attribute name to transform from
* @param $enumToCSS Lookup array of attribute values to CSS
* @param $case_sensitive Boolean case sensitivity indicator, default false
*/
public function __construct($attr, $enum_to_css, $case_sensitive = false) {
$this->attr = $attr;
$this->enumToCSS = $enum_to_css;
$this->caseSensitive = (bool) $case_sensitive;
}
public function transform($attr, $config, $context) {
if (!isset($attr[$this->attr])) return $attr;
$value = trim($attr[$this->attr]);
unset($attr[$this->attr]);
if (!$this->caseSensitive) $value = strtolower($value);
if (!isset($this->enumToCSS[$value])) {
return $attr;
}
$this->prependCSS($attr, $this->enumToCSS[$value]);
return $attr;
}
}
// vim: et sw=4 sts=4

@ -1,44 +0,0 @@
<?php
/**
* Pre-transform that changes deprecated hspace and vspace attributes to CSS
*/
class HTMLPurifier_AttrTransform_ImgSpace extends HTMLPurifier_AttrTransform {
protected $attr;
protected $css = array(
'hspace' => array('left', 'right'),
'vspace' => array('top', 'bottom')
);
public function __construct($attr) {
$this->attr = $attr;
if (!isset($this->css[$attr])) {
trigger_error(htmlspecialchars($attr) . ' is not valid space attribute');
}
}
public function transform($attr, $config, $context) {
if (!isset($attr[$this->attr])) return $attr;
$width = $this->confiscateAttr($attr, $this->attr);
// some validation could happen here
if (!isset($this->css[$this->attr])) return $attr;
$style = '';
foreach ($this->css[$this->attr] as $suffix) {
$property = "margin-$suffix";
$style .= "$property:{$width}px;";
}
$this->prependCSS($attr, $style);
return $attr;
}
}
// vim: et sw=4 sts=4

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save