Сначала у вас есть строка. JSON не является массивом, объектом или структурой данных. JSON - текстовый формат сериализации - так что причудливая строка, но все же просто строка. Декодируйте его в PHP с помощью json_decode()
.
$data = json_decode($json);
В нем вы можете найти:
Это то, что может быть закодировано в JSON. Или, точнее, это версии PHP, которые могут быть закодированы в JSON.
В них нет ничего особенного. Они не являются объектами JSON или массивами JSON. Вы расшифровали JSON - теперь у вас есть основные повседневные типы PHP .
Объекты будут экземплярами stdClass , встроенным классом, который просто generic thing , что здесь не важно.
Вы получаете доступ к свойствам одного из этих объектов так же, как и для публичных нестатических свойств любого другого объекта, например $object->property
.
$json = '
{
"type": "donut",
"name": "Cake"
}';
$yummy = json_decode($json);
echo $yummy->type; //donut
Доступ к элементам одного из этих массивов осуществляется так же, как и для любого другой массив, например $array[0]
.
$json = '
[
"Glazed",
"Chocolate with Sprinkles",
"Maple"
]';
$toppings = json_decode($json);
echo $toppings[1]; //Chocolate with Sprinkles
Итерации над ним с помощью foreach
.
foreach ($toppings as $topping) {
echo $topping, "\n";
}
Глазурованный Шоколад с спринклерами Maple
Или беспорядок с любой из встроенных функций bazillion [].
Доступ к вложенные элементы
Свойства объектов и элементов массивов могут быть больше объектов и / или массивов - вы можете просто продолжать доступ к своим свойствам и членам как обычно, например
$object->array[0]->etc
.$json = ' { "type": "donut", "name": "Cake", "toppings": [ { "id": "5002", "type": "Glazed" }, { "id": "5006", "type": "Chocolate with Sprinkles" }, { "id": "5004", "type": "Maple" } ] }'; $yummy = json_decode($json); echo $yummy->toppings[2]->id; //5004
Передача
true
в качестве второго аргумента в json_decode ()Когда вы это сделаете, вместо объектов вы получите ассоциативные массивы - массивы со строками для ключей. Снова вы получаете доступ к их элементам, как обычно, например.
$array['key']
.$json = ' { "type": "donut", "name": "Cake", "toppings": [ { "id": "5002", "type": "Glazed" }, { "id": "5006", "type": "Chocolate with Sprinkles" }, { "id": "5004", "type": "Maple" } ] }'; $yummy = json_decode($json, true); echo $yummy['toppings'][2]['type']; //Maple
Не знаю, как структурированы данные
Прочитайте документацию, независимо от того, получение JSON из.
Посмотрите на JSON - где вы видите фигурные скобки
{}
, ожидайте объект, где вы видите квадратные скобки[]
, ожидаете массив.Нажмите декодированные данные с помощью
print_r()
:$json = ' { "type": "donut", "name": "Cake", "toppings": [ { "id": "5002", "type": "Glazed" }, { "id": "5006", "type": "Chocolate with Sprinkles" }, { "id": "5004", "type": "Maple" } ] }'; $yummy = json_decode($json); print_r($yummy);
и проверьте вывод:
stdClass Object ( [type] => donut [name] => Cake [toppings] => Array ( [0] => stdClass Object ( [id] => 5002 [type] => Glazed ) [1] => stdClass Object ( [id] => 5006 [type] => Chocolate with Sprinkles ) [2] => stdClass Object ( [id] => 5004 [type] => Maple ) ) )
Он расскажет вам, где у вас есть объекты, где у вас есть массивы, а также имена и значения их членов.
Если вы можете только дойти до него до того, как потеряетесь, зайдите так далеко и нажмите , что с
print_r()
:print_r($yummy->toppings[0]);
stdClass Object ( [id] => 5002 [type] => Glazed )
Разбить проблему на части, которые легче обернуть вокруг головы.
json_decode()
возвращаетnull
Это происходит потому, что либо:
- JSON полностью состоит именно из этого,
null
.- JSON is недействителен - проверьте результат
json_last_error_msg
или введите его через JSONLi nt .- Он содержит элементы, вложенные в глубину более 512 уровней. Эта максимальная глубина по умолчанию может быть переопределена путем передачи целого числа в качестве третьего аргумента в
json_decode()
.Если вам нужно изменить максимальную глубину, вы, вероятно, решение неправильной проблемы. Узнайте, почему вы получаете такие глубоко вложенные данные (например, у службы, к которой вы обращаетесь, у которой возникает JSON, есть ошибка) и получить это, чтобы этого не произошло.
Имя свойства объекта содержит специальный символ
Иногда у вас будет имя свойства объекта, которое содержит нечто вроде дефиса
-
или знака@
, которое не может использоваться в литеральном идентификаторе. Вместо этого вы можете использовать строковый литерал в фигурных скобках для его адресации.$json = '{"@attributes":{"answer":42}}'; $thing = json_decode($json); echo $thing->{'@attributes'}->answer; //42
Если у вас есть свойство integer as: Как получить доступ к свойствам объекта с именами типа целых чисел? как ссылка.
Кто-то поставил JSON в ваш JSON
Это смешно, но это происходит - JSON закодирован как строка в вашем JSON. Декодирование, доступ к строке как обычно, декодирование , которое , и, в конечном счете, доступ к тому, что вам нужно.
$json = ' { "type": "donut", "name": "Cake", "toppings": "[{ \"type\": \"Glazed\" }, { \"type\": \"Maple\" }]" }'; $yummy = json_decode($json); $toppings = json_decode($yummy->toppings); echo $toppings[0]->type; //Glazed
Данные не помещаются в память
Если ваш JSON слишком большой для
json_decode()
, чтобы обрабатывать сразу, все начинает становиться сложным. См. Также:Как отсортировать его
См.: Ссылка: все основные способы сортировки массивов и данных в PHP .
Используя .NET 4.5 (или .NET 4.0, добавив пакет Microsoft.Net.Http из NuGet), есть более простой способ имитации запросов формы. Вот пример:
private async Task<System.IO.Stream> Upload(string actionUrl, string paramString, Stream paramFileStream, byte [] paramFileBytes)
{
HttpContent stringContent = new StringContent(paramString);
HttpContent fileStreamContent = new StreamContent(paramFileStream);
HttpContent bytesContent = new ByteArrayContent(paramFileBytes);
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(stringContent, "param1", "param1");
formData.Add(fileStreamContent, "file1", "file1");
formData.Add(bytesContent, "file2", "file2");
var response = await client.PostAsync(actionUrl, formData);
if (!response.IsSuccessStatusCode)
{
return null;
}
return await response.Content.ReadAsStreamAsync();
}
}
Вам нужно записать файл в поток запросов:
using (var reqStream = req.GetRequestStream())
{
reqStream.Write( ... ) // write the bytes of the file
}
Для отправки необработанного файла только :
using(WebClient client = new WebClient()) {
client.UploadFile(address, filePath);
}
Если вы хотите эмулировать форму браузера с помощью <input type="file"/>
, это сложнее. См. этот ответ для ответа multipart / form-data.
http://www.testproject.com/SavedFiles
- обратите внимание на //
– Marc Gravell♦
28 March 2013 в 10:04
Чтобы отправлять файлы как из массивов байтов:
private static string UploadFilesToRemoteUrl(string url, IList<byte[]> files, NameValueCollection nvc) {
string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
var request = (HttpWebRequest) WebRequest.Create(url);
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.Method = "POST";
request.KeepAlive = true;
var postQueue = new ByteArrayCustomQueue();
var formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
foreach (string key in nvc.Keys) {
var formitem = string.Format(formdataTemplate, key, nvc[key]);
var formitembytes = Encoding.UTF8.GetBytes(formitem);
postQueue.Write(formitembytes);
}
var headerTemplate = "\r\n--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
"Content-Type: application/zip\r\n\r\n";
var i = 0;
foreach (var file in files) {
var header = string.Format(headerTemplate, "file" + i, "file" + i + ".zip");
var headerbytes = Encoding.UTF8.GetBytes(header);
postQueue.Write(headerbytes);
postQueue.Write(file);
i++;
}
postQueue.Write(Encoding.UTF8.GetBytes("\r\n--" + boundary + "--"));
request.ContentLength = postQueue.Length;
using (var requestStream = request.GetRequestStream()) {
postQueue.CopyToStream(requestStream);
requestStream.Close();
}
var webResponse2 = request.GetResponse();
using (var stream2 = webResponse2.GetResponseStream())
using (var reader2 = new StreamReader(stream2)) {
var res = reader2.ReadToEnd();
webResponse2.Close();
return res;
}
}
public class ByteArrayCustomQueue {
private LinkedList<byte[]> arrays = new LinkedList<byte[]>();
/// <summary>
/// Writes the specified data.
/// </summary>
/// <param name="data">The data.</param>
public void Write(byte[] data) {
arrays.AddLast(data);
}
/// <summary>
/// Gets the length.
/// </summary>
/// <value>
/// The length.
/// </value>
public int Length { get { return arrays.Sum(x => x.Length); } }
/// <summary>
/// Copies to stream.
/// </summary>
/// <param name="requestStream">The request stream.</param>
/// <exception cref="System.NotImplementedException"></exception>
public void CopyToStream(Stream requestStream) {
foreach (var array in arrays) {
requestStream.Write(array, 0, array.Length);
}
}
}
Для меня client.UploadFile
все еще завербовал содержимое в многостраничном запросе, поэтому мне пришлось сделать это следующим образом:
using (WebClient client = new WebClient())
{
client.Headers.Add("Content-Type", "application/octet-stream");
using (Stream fileStream = File.OpenRead(filePath))
using (Stream requestStream = client.OpenWrite(new Uri(fileUploadUrl), "POST"))
{
fileStream.CopyTo(requestStream);
}
}
public string SendFile(string filePath)
{
WebResponse response = null;
try
{
string sWebAddress = "Https://www.address.com";
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(sWebAddress);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream stream = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
stream.Write(boundarybytes, 0, boundarybytes.Length);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(filePath);
stream.Write(formitembytes, 0, formitembytes.Length);
stream.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, "file", Path.GetFileName(filePath), Path.GetExtension(filePath));
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
stream.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
stream.Write(buffer, 0, bytesRead);
fileStream.Close();
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
stream.Write(trailer, 0, trailer.Length);
stream.Close();
response = wr.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream);
string responseData = streamReader.ReadToEnd();
return responseData;
}
catch (Exception ex)
{
return ex.Message;
}
finally
{
if (response != null)
response.Close();
}
}
У меня была такая же проблема, и этот следующий код отлично ответил на эту проблему:
//Identificate separator
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
//Encoding
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
//Creation and specification of the request
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url); //sVal is id for the webService
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
string sAuthorization = "login:password";//AUTHENTIFICATION BEGIN
byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(sAuthorization);
string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);
wr.Headers.Add("Authorization: Basic " + returnValue); //AUTHENTIFICATION END
Stream rs = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}"; //For the POST's format
//Writting of the file
rs.Write(boundarybytes, 0, boundarybytes.Length);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(Server.MapPath("questions.pdf"));
rs.Write(formitembytes, 0, formitembytes.Length);
rs.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, "file", "questions.pdf", contentType);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(Server.MapPath("questions.pdf"), FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
rs.Write(buffer, 0, bytesRead);
}
fileStream.Close();
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
rs.Write(trailer, 0, trailer.Length);
rs.Close();
rs = null;
WebResponse wresp = null;
try
{
//Get the response
wresp = wr.GetResponse();
Stream stream2 = wresp.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
string responseData = reader2.ReadToEnd();
}
catch (Exception ex)
{
string s = ex.Message;
}
finally
{
if (wresp != null)
{
wresp.Close();
wresp = null;
}
wr = null;
}
formData.Add()
, когда содержимое имело типStringContent
, чтобы скрипт получающего сервера распознал поля сообщения. – dAngelov 4 May 2014 в 15:41form.Add
- optional и полезен только для файлов. – StockBreak 5 March 2018 в 10:23