Funkcja header nie zadziała Ci w cron. Odpalenie skryptu przy jego pomocy jest równoznaczne z wpisaniem polecenia z palca w konsoli. To że wyślesz nagłowki nic nie da bo konsola ich nie odbierze i nie obsłuży

Możesz zrobić to w inny sposób. Skoro chcesz to aktualizować dwa razy na dobę powiedzmy między północą i 12 oraz drugi raz między 12 a północą.
Kolumnę updated ustawiasz jako typ DATETIME i zapisujesz w niej kiedy był zrobiony ostatni update użytkownika. Aby wiedzieć czy skrypt jest wykonywany pierwszy raz dla użytkownika czy drugi należy sprawdzić aktualną godzinę przy pomocy funkcji
date:
Kod
$hour = date('H')
Jeśli godzina jest między między 0 a 11 (włącznie) to mamy pierwsze, jeśli między 12 a 23 (włącznie) to drugie. Ustalenie tego jest konieczne do określenia warunku w zapytaniu do bazy, którym będziemy wyciągać użytkowników:
Kod
$date = date('Y-m-d');
if($hour >= 0 && $hour <= 11)
$date .= '00:00:00';
else
$date .= '12:00:00';
$sql = 'SELECT * FROM users WHERE updated < ' . $date . 'ORDER BY updated'; // sortujemy według tych, którzy najdłużej nie byli aktualizowani
Przy aktualizacji użytkownika w bazie danych w kolumnie updated podajemy wartość 'NOW()'. W tedy będziemy mieli zapisaną dokładną datę i godzinę, w której użytkownik został zaktualizowany
Co do samego uruchamiania skryptu to tak jak sugerowali poprzednicy uruchamiasz cron-a co określony odstęp czasu. Aby skrypty nie kolidowały tworzysz plik tymczasowy np: .updating.lock, a żeby było jeszcze bezpieczniej w nim umieszczasz aktualny czas:
Kod
file_put_contents('.updating.lock', time())
Po każdym przejściu pętli także należy zaktualizować czas znajdujący się w pliku. Dlaczego umieszczać czas w pliku? Odpowiedź jest prosta. Jeśli skrypt z jakiegoś powodu się wysypie to plik zostanie na stałe, a kolejne uruchamiane skrypty będą "myślały", że pierwszy cały czas działa, dlatego podczas uruchamiania skryptu oprócz sprawdzania czy plik istnieje można sprawdzić jaki był ostatni czas zapisu. Jeśli był wiekszy niż np 10 minut, to znaczy, że wcześniejszy skrypt się wysypał i obecny może kontynuować aktualizację.
Kod
if(file_exists('.updating.lock'))
{
$time = (int)file_get_contents('.updating.lock');
if(($time + (60 * 10)) > time()) // poprzedni skrypt działa więc wychodzimy
exit();
}