The Portuguese champions took a 10th-minute lead when James Rodriguez tapped in a cross from Hulk to put the visitors ahead.
But Zenit equalized 10 minutes later after Shirokov’s shot deflected into goal off of Jorge Fucile, who was sent off in the 45th after being shown a second yellow card.
Shirokov put the Russians ahead for good in the 63rd from a powerful left-footed shot before sending in a cross from the right nine minutes later for Danny to tap home.
Porto’s first defeat on Russia soil allowed Zenit to join it on three points.
Short link: