尝试使用Slim Framework从客户端读取Json和图像文件

时间:2017-10-13 00:41:27

标签: php android json http slim

所以,我有一个客户端移动用retrofit2做请求,并且在请求时我需要发送一个图像文件和一个json对象。像这样:

RequestBody requestJson = RequestBody.create(MediaType.parse("application/json"), new Gson().toJson(cidadao));

            MultipartBody.Part fotoBody = MultipartBody.Part.createFormData("foto", file.getName(), requestFile);
            MultipartBody.Part jsonBody = MultipartBody.Part.createFormData("cidadao", null, requestJson);

            Service service = CallService.createService(Service.class);
            Call<Void> cadastrarCidadao = service.postCidadao(UsuarioApplication.getInstance().getToken().getToken(),
                    jsonBody,
                    fotoBody);
            cadastrarCidadao.enqueue(new Callback<Void>() {
                @Override
                public void onResponse(Call<Void> call, Response<Void> response) {
                    if (response.isSuccessful()) {
                        if (response.code() == 201) {
                            dialog.dismiss();
                            FragmentManager fm = getFragmentManager();
                            fm.popBackStack();
                        }
                    } else {
                        APIError error = ErrorUtils.parseError(response);
                        new Throwable(error.getMessage());
                    }
                }

                @Override
                public void onFailure(Call<Void> call, Throwable t) {
                    Log.e("ErrorCadastro", t.getLocalizedMessage());
                    Toasty.error(getContext(), "Erro na conexão").show();
                }
            });

服务接口:

package com.example.administrador.citycaremobile.Services;

import com.example.administrador.citycaremobile.Modelo.Cidadao;
import com.example.administrador.citycaremobile.Modelo.Login;

import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Part;

public interface Service {

@POST("cidadao/cadastrar")
@Multipart
Call<Void> postCidadao(@Header("X-Token") String token,
                       @Part MultipartBody.Part cidadao,
                       @Part MultipartBody.Part foto);

@PUT("cidadao/put")
Call<Boolean> putUsuario(@Header("Content-type") String content,
                         @Header("X-Token") String token,
                         @Body Cidadao cidadao);

@Headers("content-type:application/json")
@GET("auth")
Call<Token> autentication();

//Login
@POST("login")
Call<Object> login(@Header("Content-type") String content,
                   @Header("X-Token") String token,
                   @Body Login login);
}

在服务方面,有一个带有Slim框架的PHP,问题是......当我尝试使用$ request-&gt; getParam()获取json时,他们会返回一个包含所有字符的数组,其中每个character是该数组上的一个项目。

Ex:如果显示返回$ jsonParam [0],他返回给我&#34; {&#34;,我试图将所有数组解析为一个String但是不成功,尝试了implode方法,在param上尝试了json_decode但没什么用。

有服务方法:

$app -> post('/cidadao/cadastrar', function(Request $request, Response $response) use ($app){
        //Container do EntityManager
        $entityManager = $this -> get('em');
        $json = $request -> getParam('cidadao');

        try{
            //Instância da entidade Login
            $login = new Login();
            //recuperando o parâmetro objeto login do json
            $fk_login_cidadao = $json['fk_login_cidadao'];
            //setando valores do objeto login
            $login ->setLogin($fk_login_cidadao['login']);
            $login ->setEmail($fk_login_cidadao['email']);
            $login ->setSenha($fk_login_cidadao['senha']);
            $login ->setStatus_login($fk_login_cidadao['status_login']);
            $login ->setAsAdministrador($fk_login_cidadao['administrador']);

            //salvando login
            $entityManager->persist($login);
            $entityManager->flush();
            //buscando login recém salvo
            $loginRepository = $entityManager->getRepository('App\Models\Entity\Login');
            //pegando login
            $loginCidadao = $loginRepository->find($login->getId_login());
            //Salvar foto
            $files = $request->getUploadedFiles();
            $newimage = $files['foto'];
            if ($newimage->getError() === UPLOAD_ERR_OK) {
                $uploadFileName = $newimage->getClientFilename();
                $type = $newimage->getClientMediaType();
                $name = uniqid('img-' . date('d-m-y') . '-');
                $name .= $newimage->getClientFilename();
                //  $imgs[] = array('url' => '/Photos/' . $name);
                //local server
                $newimage->moveTo("/home/citycare/public_html/Imgs/user/$name");#/home/citycare/Imgs/User/$name
                //localdev
                $photoURL = "/home/citycare/public_html/Imgs/user/$name";#/home/citycare/Imgs/User/$name
            }
            //Instância da entidade Cidadao
            $cidadao = new Cidadao();
            //setando valores do objeto cidadao
            $cidadao ->setFk_login_cidadao($loginCidadao);
            $cidadao->setNome($request->getParam('nome'));
            $cidadao->setSexo($request->getParam('sexo'));
            $cidadao ->setSobrenome($request->getParam('sobrenome'));
            $cidadao ->setEstado($request->getParam('estado'));
            $cidadao ->setCidade($request->getParam('cidade'));
            $cidadao ->setDir_foto_usuario($request->getParam($photoURL));
            $entityManager->persist($cidadao);
            $entityManager->flush();
            //retornando confirmação do evento completo
            $return = $response->withStatus(201)->withHeader('Content-type', 'application/json');


        } catch (Exception $ex){
            //código e mensagem do erro
            throw new Exception($ex->getMessage(), $ex->getCode());
        }
        return $return;
});

图像处理正常。

HTTP请求:

10-14 03:35:38.772 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --> POST http://servico.projetocitycare.com.br/cidadao/cadastrar http/1.1
10-14 03:35:38.773 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Type: multipart/form-data; boundary=58c96b8f-a56e-4b42-8052-10d48c583cc4
10-14 03:35:38.776 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Length: 69178
10-14 03:35:38.777 19151-9871/com.example.administrador.citycaremobile D/OkHttp: X-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoicm9vdCIsInNlbmhhIjoiY2FyZWNpdHkiLCJleHAiOjE1MDc5NjMwOTUsImlwIjoiMTc3LjM3LjIyOC4xNDIifQ.ePeHn_YgmRfach6B1v4JC75147ixRwrjdoUvEjpPKRQ
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --58c96b8f-a56e-4b42-8052-10d48c583cc4
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Disposition: form-data; name="cidadao"
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Type: application/json; charset=utf-8
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Length: 239
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: {"cidade":"Alto Rio Novo","estado":"Espírito Santo","fk_login_cidadao":{"administrador":false,"email":"ekekejj@mks.xkm","login":"kddjsjn","senha":"jskeieej","status_login":true},"nome":"neenenem","sexo":"Masculino","sobrenome":"memekekk"}
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --58c96b8f-a56e-4b42-8052-10d48c583cc4
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Disposition: form-data; name="foto"; filename="cropped83912673.jpg"
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Type: multipart/form-data
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Length: 68558
10-14 03:35:38.788 19151-9871/com.example.administrador.citycaremobile D/OkHttp: ������JFIF����������������C��
10-14 03:35:38.800 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --58c96b8f-a56e-4b42-8052-10d48c583cc4--
10-14 03:35:38.800 19151-9871/com.example.administrador.citycaremobile D/OkHttp: --> END POST (69178-byte body)

HTTP响应:

10-14 03:35:39.675 19151-9871/com.example.administrador.citycaremobile D/OkHttp: <-- 500 Internal Server Error http://servico.projetocitycare.com.br/cidadao/cadastrar (874ms)
10-14 03:35:39.676 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Server: nginx
10-14 03:35:39.676 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Date: Sat, 14 Oct 2017 06:35:39 GMT
10-14 03:35:39.676 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Content-Type: application/json;charset=utf-8
10-14 03:35:39.677 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Transfer-Encoding: chunked
10-14 03:35:39.677 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Connection: keep-alive
10-14 03:35:39.678 19151-9871/com.example.administrador.citycaremobile D/OkHttp: Upgrade: h2,h2c
10-14 03:35:39.685 19151-9871/com.example.administrador.citycaremobile D/OkHttp:     {"message":"An exception occurred while executing 'INSERT INTO login (email, login, senha, status_login, administrador) VALUES (?, ?, ?, ?, ?)' with params [\"{\", \"{\", \"ew==\", \"{\", \"{\"]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '{' for key 'UNIQ_AA08CB10E7927C74'"}
10-14 03:35:39.686 19151-9871/com.example.administrador.citycaremobile D/OkHttp: <-- END HTTP (310-byte body)
杰森发的是这样的:

    {"cidade":"Brasília",
     "estado":"Distrito Federal",
     "fk_login_cidadao":{ "administrador":false,
                          "email":"b@b.com",
                          "login":"jhon",
                          "senha":"182873728192",
                          "status_login":true},
     "nome":"Jhon",
     "sexo":"Masculino",
     "sobrenome":"James"}

2 个答案:

答案 0 :(得分:0)

您的请求正文大部分都是合理的,除此之外:Content-Transfer-Encoding: binary我不明白为什么retrofit2会将其添加到form-data。但是,我并不认为这是您遇到的错误。

我认为PHP没有正确解析form-data因为这个额外的位。但后来我意识到你正在解析JSON并将其作为数组访问。您的json字符串是一个对象,将由PHP JSON解码器解释。

总而言之,您应该像这样访问数据(json)对象的值:$json->fk_login_cidadao而不是这样:$json['fk_login_cidadao']。这也适用于其余的价值和密钥对。

如果您想测试我的理论,只需将参数$request -> getParam('cidadao')的内容记录或写入文件。

答案 1 :(得分:0)

所以,经过多次尝试,在$ json上使用var_dump()我看到请求没有被框架解码,我不知道为什么,所以我需要手动解码并使用Object而不是数组。最后API端代码保持这样:

$app ->post('/cidadao/cadastrar', function(Request $request, Response $response) use ($app){
        //Container do EntityManager
        $entityManager = $this -> get('em');

        $json = $request->getParam('cidadao');
        $json = json_decode($json);


        try{
            //Instância da entidade Login
            $login = new Login();
            //recuperando o parâmetro objeto login do json
            $fk_login_cidadao = $json -> fk_login_cidadao;
            //setando valores do objeto login
            $login ->setLogin($fk_login_cidadao -> login);
            $login ->setEmail($fk_login_cidadao -> email);
            $login ->setSenha($fk_login_cidadao -> senha);
            $login ->setStatus_login($fk_login_cidadao -> status_login);
            $login ->setAsAdministrador($fk_login_cidadao -> administrador);

            //salvando login
            $entityManager->persist($login);
            $entityManager->flush();
            //buscando login recém salvo
            $loginRepository = $entityManager->getRepository('App\Models\Entity\Login');
            //pegando login
            $loginCidadao = $loginRepository->find($login->getId_login());
            //Salvar foto
            $files = $request->getUploadedFiles();
            $newimage = $files['foto'];
            if ($newimage->getError() === UPLOAD_ERR_OK) {
                $uploadFileName = $newimage->getClientFilename();
                $type = $newimage->getClientMediaType();
                $name = uniqid('img-' . date('d-m-y') . '-');
                $name .= $newimage->getClientFilename();
                //  $imgs[] = array('url' => '/Photos/' . $name);
                //local server
                $newimage->moveTo("/home/citycare//imgs/$name");#/home/citycare/Imgs/User/$name
                //localdev
                $photoURL = "/home/citycare//imgs/$name";#/home/citycare/Imgs/User/$name
            }
            //Instância da entidade Cidadao
            $cidadao = new Cidadao();
            //setando valores do objeto cidadao
            $cidadao ->setFk_login_cidadao($loginCidadao);
            $cidadao->setNome($json -> nome);
            $cidadao->setSexo($json -> sexo);
            $cidadao ->setSobrenome($json -> sobrenome);
            $cidadao ->setEstado($json -> estado);
            $cidadao ->setCidade($json -> cidade);
            $cidadao ->setDir_foto_usuario($photoURL);
            $entityManager->persist($cidadao);
            $entityManager->flush();
            //retornando confirmação do evento completo
            $return = $response->withStatus(201)->withHeader('Content-type', 'application/json');


        } catch (Exception $ex){
            //código e mensagem do erro
            throw new Exception($ex->getMessage(), $ex->getCode());
        }
        return $return;
});