/src/Composer/Json/JsonFile.php

https://github.com/kelvinj/composer · PHP · 138 lines · 81 code · 14 blank · 43 comment · 8 complexity · 1662538215c1111302391f0b323e6f68 MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Json;
  12. use Composer\Repository\RepositoryManager;
  13. use Composer\Composer;
  14. /**
  15. * Reads/writes json files.
  16. *
  17. * @author Konstantin Kudryashiv <ever.zet@gmail.com>
  18. */
  19. class JsonFile
  20. {
  21. private $path;
  22. /**
  23. * Initializes json file reader/parser.
  24. *
  25. * @param string $lockFile path to a lockfile
  26. */
  27. public function __construct($path)
  28. {
  29. $this->path = $path;
  30. }
  31. public function getPath()
  32. {
  33. return $this->path;
  34. }
  35. /**
  36. * Checks whether json file exists.
  37. *
  38. * @return Boolean
  39. */
  40. public function exists()
  41. {
  42. return is_file($this->path);
  43. }
  44. /**
  45. * Reads json file.
  46. *
  47. * @param string $json path or json string
  48. *
  49. * @return array
  50. */
  51. public function read()
  52. {
  53. $context = stream_context_create(array(
  54. 'http' => array('header' => 'User-Agent: Composer/'.Composer::VERSION."\r\n")
  55. ));
  56. $json = file_get_contents($this->path, false, $context);
  57. if (!$json) {
  58. throw new \RuntimeException('Could not read '.$this->path.', you are probably offline');
  59. }
  60. return static::parseJson($json);
  61. }
  62. /**
  63. * Writes json file.
  64. *
  65. * @param array $hash writes hash into json file
  66. */
  67. public function write(array $hash)
  68. {
  69. $dir = dirname($this->path);
  70. if (!is_dir($dir)) {
  71. if (file_exists($dir)) {
  72. throw new \UnexpectedValueException(
  73. $dir.' exists and is not a directory.'
  74. );
  75. }
  76. if (!mkdir($dir, 0777, true)) {
  77. throw new \UnexpectedValueException(
  78. $dir.' does not exist and could not be created.'
  79. );
  80. }
  81. }
  82. file_put_contents($this->path, json_encode($hash));
  83. }
  84. /**
  85. * Parses json string and returns hash.
  86. *
  87. * @param string $json json string
  88. *
  89. * @return array
  90. */
  91. public static function parseJson($json)
  92. {
  93. $data = json_decode($json, true);
  94. if (null === $data && 'null' !== strtolower($json)) {
  95. switch (json_last_error()) {
  96. case JSON_ERROR_NONE:
  97. $msg = 'No error has occurred, is your composer.json file empty?';
  98. break;
  99. case JSON_ERROR_DEPTH:
  100. $msg = 'The maximum stack depth has been exceeded';
  101. break;
  102. case JSON_ERROR_STATE_MISMATCH:
  103. $msg = 'Invalid or malformed JSON';
  104. break;
  105. case JSON_ERROR_CTRL_CHAR:
  106. $msg = 'Control character error, possibly incorrectly encoded';
  107. break;
  108. case JSON_ERROR_SYNTAX:
  109. $msg = 'Syntax error';
  110. if (preg_match('#["}\]]\s*(,)\s*\}#', $json, $match, PREG_OFFSET_CAPTURE)) {
  111. $msg .= ', extra comma on line '.(substr_count(substr($json, 0, $match[1][1]), "\n")+1);
  112. } elseif (preg_match('#(\'.+?\' *:|: *\'.+?\')#', $json, $match, PREG_OFFSET_CAPTURE)) {
  113. $msg .= ', use double quotes (") instead of single quotes (\') on line '.(substr_count(substr($json, 0, $match[1][1]), "\n")+1);
  114. }
  115. break;
  116. case JSON_ERROR_UTF8:
  117. $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
  118. break;
  119. }
  120. throw new \UnexpectedValueException('Incorrect composer.json file: '.$msg);
  121. }
  122. return $data;
  123. }
  124. }