かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

生PHPで application/jsonで送られたデータを取得したい

Content-Type application/json で送られてくるデータを生 PHP で取得する場合のメモ
フレームワーク使ってたら、この方法を使うことは無さそうだけど、メモとして…

こんな感じのフロントから送られるデータを扱いたい

const data = {
  email: 'example@example.com',
  password: 'password',
}
await axios.post(API, data, {
  headers: {
    'Content-Type': 'application/json',
  },
});

Content-Type: application/json で送られたデータは $_POST では上手く取得できません。

PHPjson で送られたデータを取得するには file_get_contents('php://input') を使う

file_get_contents('php://input')JSON データを取得してjson_decode連想配列形式にして送られたデータを取得する

<?php
$json = file_get_contents('php://input');
$params = json_decode($json, true);
$email = $params['email']; // => "example@example.com"
$password = $params['password']; // => "password"

₍ ᐢ. ̫ .ᐢ ₎👌  
おわり


[参考]

Laravel: Up & Running: A Framework for Building Modern PHP Apps

Laravel: Up & Running: A Framework for Building Modern PHP Apps

  • 作者:Stauffer, Matt
  • 発売日: 2019/04/23
  • メディア: ペーパーバック

PHPフレームワーク Laravel入門

PHPフレームワーク Laravel入門

JavaScript (SPA) PHP axios でフォームデータを送る時に気をつけること

$_POSTfilter_input でデータを取得しているようなPHPのバックエンドにフォームデータを axios で送信する時 Content-Type を application/x-www-form-urlencoded にするだけでは上手くいきません。

🙅‍♀️ Content-Type: application/x-www-form-urlencoded でも上手く行かない例

バックエンド (PHP)

<?php
addRoute('POST', '/login', login);

function login() {
  $email = filter_input(INPUT_POST, 'email');
  $password = filter_input(INPUT_POST, 'password');
  // ログイン処理 
}

フロントのフォーム送信部分

const data = {
  email: 'example@example.com',
  password: 'password',
};
await axiso.post('/login', data, {
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
});

バックエンドで $email, $password が空文字列になるので上手く行かない。
この送り方だと $POST が次のような形になっている

<?php
function login() {
  var_dump($_POST);
  // => {{"email":"example2@example_com","password":"123456"}: ""}
}

🙆‍♀️ axios で フォームデータを送る時は URLSearchParams を使う

送信するデータを URLSearchParams の形式にする必要がある

const data = {
  email: 'example@example.com',
  password: 'password',
};

const params = new URLSearchParams();
Object.keys(data).forEach(function(key) {
  params.append(key, this[key]);
}, data);

await axiso.post('/login', params, {
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
});

👇
$_POST{email: "example2@example.com", password: "123456"} という形になるので、バックエンドの $_POSTfilter_input でフロントから送られたデータが正しく取得できるようになりました! ₍ ᐢ. ̫ .ᐢ ₎👌

公式のドキュメントには qs というパッケージを使う方法も載っていました。

import qs from 'qs';
const data = { 'bar': 123 };
const options = {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  data: qs.stringify(data),
  url,
};
axios(options);
cf. GitHub - axios/axios: Promise based HTTP client for the browser and node.js

所感

ちゃんとドキュメント読もうって事でした。
思い出せば、jQueryajax だと Object をそのまま送っても $_POST で取得できていた記憶があったので、jQuery 君、今までは君がいい感じに変換してくれてたんだね…って思ったのでした。


[参考]

北北西に曇と往け 1巻 (HARTA COMIX)

北北西に曇と往け 1巻 (HARTA COMIX)

アイスランド行きたい

React Hooks forwardRef を使わずに子コンポーネントにrefを渡す

React で子コンポーネントを ref で触りたい時、forwardRef APIを使うように言われます。

例えばボタンをクリックしたらフォーカスされるインプットフィールドだとこんな感じ。

import React, { useRef } from 'react';

const InputField = React.forwardRef({placeholder}, ref) => {
  return <input ref={ref} placeholder={placeholder} />
});

const App = () => {
  const inputRef = useRef(null);
  const onFocus = () => {
    inputRef.current.focus();
  };
  return (
    <>
      <InputField ref={inputRef} placeholder={forwardRef Input Field} />
      <button onClick={onFocus}>Focus</button>
    </>
  );
};

ref という名前で渡さなければ forwardRef API を使わなくても問題なく動作する

forwardRef を使わずに ref={ref} のような props を渡していると Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? という warning が発生するのですが、子コンポーネントに渡す props のキーが ref という名前でなければ warning も発生せず問題なく動作してしまうみたいです。

import React, { useRef } from 'react';

const InputField = ({placeholder, elmRef}) => {
  return <input ref={elmRef} placeholder={placeholder} />
};

const App = () => {
  const inputRef = useRef(null);
  const onFocus = () => {
    inputRef.current.focus();
  };
  return (
    <>
      <InputField elmRef={inputRef} placeholder={Input Field without forwardRef} />
      <button onClick={onFocus}>Focus</button>
    </>
  );
};

forwardRef API を使った方が速いとかあるのでしょうか?
チョット判らないのですが、これでも forwardRef を使った時と同じように問題なく動作します。

サンプル

See the Pen React forwardRef vs useRef by KIKIKI (@kikiki_kiki) on CodePen.

TypeScript だと渡される props は RefObject なのでこんな感じ

import React, { useRef, RefObject } from 'react';

type InputFieldProps = {
  placeholder: string;
  elmRef: RefObject<HTMLInputElement>
};

const InputField = ({placeholder, elmRef}: InputFieldProps) => {
  return <input ref={elmRef} placeholder={placeholder} />
};

const App = () => {
  const inputRef = useRef<HTMLInputElement>(null);
  const onFocus = () => {
    inputRef.current && inputRef.current.focus();
  };
  return (
    <>
      <InputField elmRef={inputRef} placeholder={Input Field without forwardRef} />
      <button onClick={onFocus}>Focus</button>
    </>
  );
};

おわり


マイ・インターン(字幕版)

マイ・インターン(字幕版)

  • 発売日: 2016/01/13
  • メディア: Prime Video
👆とても面白かったです