The BFS here is the same machine as 1091 — levels are distances, mark on push. What is new is the exit predicate: a border cell is an exit unless it is the entrance. Get that wrong and every maze whose entrance sits on the border answers 0. The fix that needs no guard at all is to test the neighbour as you step onto it, after the entrance has already been sealed.
maze[er][ec] = '+' BEFORE the BFS starts prevents an immediate 0-step false exit and guarantees O(mn) shortest path.
"Because all steps between adjacent cells cost 1 unit of distance, BFS guarantees we find the nearest exit in minimal steps."
"The entrance often starts on the border. If we simply check 'is cell on border' on pop without checking if it's the entrance, we return 0 immediately!"
"Instead of carrying a verbose !(r == er && c == ec) check on every step, simply seal maze[er][ec] = '+' upfront. Now any cell we can step onto is guaranteed not to be the entrance!"
"Every cell is enqueued at most once. Total time is $O(m \cdot n)$ and auxiliary space is $O(m \cdot n)$ queue memory."