Разобрался, тут две ошибки:
1) Я отправляю на сервер не форму, а файл, правильно так, это поечатка:
return this.http.post<HttpResponse<any>>(url, formData, httpOptions);
// вместо
return this.http.post<HttpResponse<any>>(url, file, httpOptions);
2) Основная причина в Content-Type. При отправке бэк с PHP, если указать любой, даже пустой, Content-Type, то данные прийдут в тело запроса php://input, без заголовка в $_FILES.