@@ -27,10 +27,21 @@ final class Json extends File
2727 * @param string $file
2828 * @param bool $isArray
2929 * @return mixed
30+ * @throws \InvalidArgumentException When file is invalid
31+ * @throws \RuntimeException When JSON parsing fails
3032 */
3133 public static function parse (string $ file , bool $ isArray = false ) : mixed
3234 {
33- return self ::decode (self ::r ($ file ), $ isArray );
35+ if ( empty ($ file ) ) {
36+ throw new \InvalidArgumentException ('File path must be a non-empty string ' );
37+ }
38+
39+ $ content = self ::r ($ file );
40+ if ( $ content === false || $ content === null ) {
41+ throw new \RuntimeException ("Unable to read file: {$ file }" );
42+ }
43+
44+ return self ::decode ($ content , $ isArray );
3445 }
3546
3647 /**
@@ -40,10 +51,28 @@ public static function parse(string $file, bool $isArray = false) : mixed
4051 * @param string $value
4152 * @param bool $isArray
4253 * @return mixed
54+ * @throws \InvalidArgumentException When input is invalid
55+ * @throws \RuntimeException When JSON decoding fails
4356 */
4457 public static function decode (string $ value , bool $ isArray = false ) : mixed
4558 {
46- return json_decode ($ value , $ isArray );
59+ // Input validation
60+ if ( empty ($ value ) ) {
61+ throw new \InvalidArgumentException ('JSON string cannot be empty ' );
62+ }
63+
64+ // Security
65+ $ maxDepth = 512 ;
66+ $ result = json_decode ($ value , $ isArray , $ maxDepth );
67+
68+ // Check for errors
69+ $ error = self ::lastError ();
70+ if ( $ error !== JSON_ERROR_NONE ) {
71+ $ errorMessage = self ::getError ($ error );
72+ throw new \RuntimeException ("JSON decode error: {$ errorMessage }" );
73+ }
74+
75+ return $ result ;
4776 }
4877
4978 /**
@@ -52,6 +81,8 @@ public static function decode(string $value, bool $isArray = false) : mixed
5281 * @access public
5382 * @param mixed $value
5483 * @return mixed
84+ * @throws \InvalidArgumentException When value cannot be encoded
85+ * @throws \RuntimeException When JSON encoding fails
5586 */
5687 public static function encode ($ value ) : mixed
5788 {
@@ -70,9 +101,96 @@ public static function encode($value) : mixed
70101 * @param int $flags
71102 * @param int $depth
72103 * @return mixed
104+ * @throws \InvalidArgumentException When parameters are invalid
105+ * @throws \RuntimeException When JSON encoding fails
73106 */
74107 public static function format ($ value , int $ flags = 64 | 256 , int $ depth = 512 ) : mixed
75108 {
76- return json_encode ($ value , $ flags , $ depth );
109+ // Validate depth parameter
110+ if ( $ depth < 1 || $ depth > 2147483647 ) {
111+ throw new \InvalidArgumentException ('Depth must be between 1 and 2147483647 ' );
112+ }
113+
114+ // Validate value is encodable
115+ if ( is_resource ($ value ) ) {
116+ throw new \InvalidArgumentException ('Cannot encode resource type ' );
117+ }
118+
119+ // Encode with error handling
120+ $ result = json_encode ($ value , $ flags , $ depth );
121+
122+ // Check for errors
123+ $ error = self ::lastError ();
124+ if ( $ error !== JSON_ERROR_NONE ) {
125+ $ errorMessage = self ::getError ($ error );
126+ throw new \RuntimeException ("JSON encode error: {$ errorMessage }" );
127+ }
128+
129+ return $ result ;
130+ }
131+
132+ /**
133+ * Validate JSON string.
134+ *
135+ * @access public
136+ * @param string $value
137+ * @return bool
138+ */
139+ public static function isValid (string $ value ) : bool
140+ {
141+ if ( empty ($ value ) ) {
142+ return false ;
143+ }
144+
145+ json_decode ($ value );
146+ return self ::lastError () === JSON_ERROR_NONE ;
147+ }
148+
149+ /**
150+ * Get JSON last error.
151+ *
152+ * @access public
153+ * @return int
154+ */
155+ public static function lastError () : int
156+ {
157+ return json_last_error ();
158+ }
159+
160+ /**
161+ * Get human-readable JSON error message.
162+ *
163+ * @access private
164+ * @param int $error
165+ * @return string
166+ */
167+ private static function getError (int $ error ) : string
168+ {
169+ switch ($ error ) {
170+ case JSON_ERROR_NONE :
171+ return 'No error ' ;
172+ case JSON_ERROR_DEPTH :
173+ return 'Maximum stack depth exceeded ' ;
174+ case JSON_ERROR_STATE_MISMATCH :
175+ return 'State mismatch (invalid or malformed JSON) ' ;
176+ case JSON_ERROR_CTRL_CHAR :
177+ return 'Control character error ' ;
178+ case JSON_ERROR_SYNTAX :
179+ return 'Syntax error, malformed JSON ' ;
180+ case JSON_ERROR_UTF8 :
181+ return 'Malformed UTF-8 characters ' ;
182+ case JSON_ERROR_RECURSION :
183+ return 'One or more recursive references in the value to be encoded ' ;
184+ case JSON_ERROR_INF_OR_NAN :
185+ return 'One or more NAN or INF values in the value to be encoded ' ;
186+ case JSON_ERROR_UNSUPPORTED_TYPE :
187+ return 'A value of a type that cannot be encoded was given ' ;
188+ case JSON_ERROR_INVALID_PROPERTY_NAME :
189+ return 'A property name that cannot be encoded was given ' ;
190+ case JSON_ERROR_UTF16 :
191+ return 'Malformed UTF-16 characters ' ;
192+ default :
193+ return "Unknown JSON error (code: {$ error }) " ;
194+ }
77195 }
78196}
0 commit comments